diff --git a/js/table/recalculate-column-width.ts b/js/table/recalculate-column-width.ts index 7bce48da1b..1aef995e2b 100644 --- a/js/table/recalculate-column-width.ts +++ b/js/table/recalculate-column-width.ts @@ -1,9 +1,134 @@ -import isNumber from 'lodash/isNumber'; -import { BaseTableCol } from './types'; +import { BaseTableCol, ThMap } from './types'; +import { getColWidthAttr } from './utils'; -export default function recalculateColumnWidth>( +/** + * 填充未设置width属性的列 + * @param columns 当前表格所有列 + * @param missingWidthCols 未设置width属性的列 + * @param thWidthList 列宽记录字典 + * @param tableLayout 表格布局 + * @param actualWidth 各列实际总列宽 + * @param tableWidth 表格总宽度 + */ +const setMissingColumnWidth = >( columns: T[], + missingWidthCols: T[], + thWidthList: ThMap, + tableLayout: string, + actualWidth: number, + tableWidth: number +) : void => { + const thMap = thWidthList; + // 当前列宽总宽度小于表宽,将剩余宽度平均分配给未指定宽度的列 + if (actualWidth < tableWidth) { + let widthDiff = tableWidth - actualWidth; + const remainCols: T[] = []; + // 优先保证设置了minWidth的列满足最小宽度 + missingWidthCols.forEach((col) => { + const minWidth = getColWidthAttr(col, 'minWidth'); + if (minWidth) { + thMap[col.colKey] = minWidth; + widthDiff -= minWidth; + } else { + remainCols.push(col); + } + }); + + // 如果剩余宽度 > 0 + if (widthDiff > 0) { + // 如果存在未设置minWidth的列,这些列均分剩余宽度 + if (remainCols.length) { + const avgWidth = widthDiff / remainCols.length; + remainCols.forEach((col) => { + thMap[col.colKey] = avgWidth; + }); + } else { + // 否则所有列均分剩余宽度 + const avgWidth = widthDiff / missingWidthCols.length; + missingWidthCols.forEach((col) => { + thMap[col.colKey] += avgWidth; + }); + } + } else { + // 剩余宽度 <= 0, 所有剩余列默认填充100px + remainCols.forEach((col) => { + thMap[col.colKey] = 100; + }); + } + } else if (tableLayout === 'fixed') { + // 当前列表总宽度大于等于表宽,且当前排版模式为fixed,默认填充minWidth || 100px + missingWidthCols.forEach((col) => { + thMap[col.colKey] = getColWidthAttr(col, 'minWidth') || 100; + }); + } else { + // 当前列表总宽度大于等于表宽,且当前排版模式为aut + // 默认填充minWidth || 100px,然后按比例重新分配各列宽度 + let extraWidth = 0; + missingWidthCols.forEach((col) => { + extraWidth += getColWidthAttr(col, 'minWidth') || 100; + }); + const totalWidth = extraWidth + actualWidth; + columns.forEach((col) => { + if (!thMap[col.colKey]) { + const colWidth = getColWidthAttr(col, 'minWidth') || 100; + thMap[col.colKey] = (colWidth / totalWidth) * tableWidth; + } else { + thMap[col.colKey] = (thMap[col.colKey] / totalWidth) * tableWidth; + } + }); + } +}; + +/** + * 设置所有列的宽度 + * @param columns 当前表格所有列 + * @param thWidthList 列宽记录字典 + * @param actualWidth 各列实际总列宽 + * @param tableWidth 表格总宽度 + * @param notCalculateWidthCols 不需要参与计算的列id + */ +const setNormalColumnWidth = >( + columns: T[], + thWidthList: ThMap, + actualWidth: number, + tableWidth: number, + notCalculateWidthCols: string[] +) : void => { + const thMap = thWidthList; + columns.forEach((col) => { + if (notCalculateWidthCols.includes(col.colKey)) return; + thMap[col.colKey] = (thMap[col.colKey] / actualWidth) * tableWidth; + }); +}; + +/** + * 表格未初始化时默认填充各列宽度 + * @param missingWidthCols 未设置width属性的列 + * @param thWidthList 列宽记录字典 + */ +const setInitialColumnWidth = >( + missingWidthCols: T[], thWidthList: { [colKey: string]: number }, +) : void => { + const thMap = thWidthList; + // 表格宽度未初始化,默认填充minWidth || 100px + missingWidthCols.forEach((col) => { + thMap[col.colKey] = getColWidthAttr(col, 'minWidth') || 100; + }); +}; + +/** + * 重新按规则分配各列宽度 + * @param columns 当前表格所有列 + * @param thWidthList 列宽记录字典 + * @param tableLayout 表格布局 + * @param tableElmWidth 表格宽度 + * @param notCalculateWidthCols 不需要参与计算的列 + * @param callback 回调函数 + */ +export default function recalculateColumnWidth>( + columns: T[], + thWidthList: ThMap, tableLayout: string, tableElmWidth: number, notCalculateWidthCols: string[], @@ -11,12 +136,12 @@ export default function recalculateColumnWidth>( ): void { let actualWidth = 0; const missingWidthCols: T[] = []; - const thMap: { [colKey: string]: number } = {}; + const thMap: ThMap = {}; // 计算现有列的列宽总和 columns.forEach((col) => { if (!thWidthList[col.colKey]) { - thMap[col.colKey] = isNumber(col.width) ? col.width : parseFloat(col.width); + thMap[col.colKey] = getColWidthAttr(col, 'width'); } else { thMap[col.colKey] = thWidthList[col.colKey]; } @@ -34,31 +159,14 @@ export default function recalculateColumnWidth>( if (tableWidth > 0) { // 存在没有指定列宽的列 if (missingWidthCols.length) { - // 当前列宽总宽度小于表宽,将剩余宽度平均分配给未指定宽度的列 - if (actualWidth < tableWidth) { - const widthDiff = tableWidth - actualWidth; - const avgWidth = widthDiff / missingWidthCols.length; - missingWidthCols.forEach((col) => { - thMap[col.colKey] = avgWidth; - }); - } else if (tableLayout === 'fixed') { - // 当前列表总宽度大于等于表宽,且当前排版模式为fixed,默认填充100px - missingWidthCols.forEach((col) => { - const originWidth = thMap[col.colKey] || 100; - thMap[col.colKey] = isNumber(originWidth) ? originWidth : parseFloat(originWidth); - }); - } else { - // 当前列表总宽度大于等于表宽,且当前排版模式为auto,默认填充100px,然后按比例重新分配各列宽度 - const extraWidth = missingWidthCols.length * 100; - const totalWidth = extraWidth + actualWidth; - columns.forEach((col) => { - if (!thMap[col.colKey]) { - thMap[col.colKey] = (100 / totalWidth) * tableWidth; - } else { - thMap[col.colKey] = (thMap[col.colKey] / totalWidth) * tableWidth; - } - }); - } + setMissingColumnWidth( + columns, + missingWidthCols, + thMap, + tableLayout, + actualWidth, + tableWidth + ); needUpdate = true; } else { // 所有列都已经指定宽度 @@ -73,20 +181,18 @@ export default function recalculateColumnWidth>( } // 重新计算其他列的宽度,按表格剩余宽度进行按比例分配 if (actualWidth !== tableWidth || notCalculateWidthCols.length) { - columns.forEach((col) => { - if (notCalculateWidthCols.includes(col.colKey)) return; - thMap[col.colKey] = (thMap[col.colKey] / actualWidth) * tableWidth; - }); + setNormalColumnWidth( + columns, + thMap, + actualWidth, + tableWidth, + notCalculateWidthCols + ); needUpdate = true; } } } else { - // 表格宽度未初始化,默认填充100px - missingWidthCols.forEach((col) => { - const originWidth = thMap[col.colKey] || 100; - thMap[col.colKey] = isNumber(originWidth) ? originWidth : parseFloat(originWidth); - }); - + setInitialColumnWidth(missingWidthCols, thMap); needUpdate = true; } diff --git a/js/table/set-column-width-by-drag.ts b/js/table/set-column-width-by-drag.ts index 041738e275..dd7e74b61a 100644 --- a/js/table/set-column-width-by-drag.ts +++ b/js/table/set-column-width-by-drag.ts @@ -1,6 +1,11 @@ -import isNumber from 'lodash/isNumber'; -import { BaseTableCol } from './types'; +import { BaseTableCol, ThMap } from './types'; +import { getColWidthAttr } from './utils'; +/** + * 获取某一列的所有子列 + * @param col 表格某一列 + * @returns 当前列的所有子列 + */ const findAllChildren = >(col: T): T[] => { const loopQue: T[] = []; const result: T[] = []; @@ -18,15 +23,23 @@ const findAllChildren = >(col: T): T[] => { return result; }; +/** + * 更新拖动后的列宽记录 + * @param dragCol 被拖动的列 + * @param dragWidth 拖动大小 + * @param effectCol 受影响的列 + * @param options 配置参数 + * @param callback 回调函数 + */ export default function setThWidthListByColumnDrag>( dragCol: T, dragWidth: number, effectCol: T, options: { - getThWidthList: () => { [colKey: string]: number }, + getThWidthList: () => ThMap, DEFAULT_MIN_WIDTH: number }, - callback: (widthMap: { [colKey: string]: number }, colKeys: string[]) => void + callback: (widthMap: ThMap, colKeys: string[]) => void ): void { const { getThWidthList, DEFAULT_MIN_WIDTH } = options; const thWidthList = getThWidthList(); @@ -54,17 +67,18 @@ export default function setThWidthListByColumnDrag>( // 根据多级表头的叶节点计算实际宽度(拖动列) dragChildrenCols.forEach((child) => { - const defaultWidth = isNumber(child.width) ? child.width : parseFloat(child.width); - oldWidth += thWidthList[child.colKey] || defaultWidth; + oldWidth += thWidthList[child.colKey] || getColWidthAttr(child, 'width'); notCalculateCols.push(child.colKey); }); // 根据多级表头的叶节点计算实际宽度(受影响的列) effectChildrenCols.forEach((child) => { - const defaultWidth = isNumber(child.width) ? child.width : parseFloat(child.width); - oldEffectWidth += thWidthList[child.colKey] || defaultWidth; + oldEffectWidth += thWidthList[child.colKey] || getColWidthAttr(child, 'width'); notCalculateCols.push(child.colKey); - effectColsMinWidth += child.resize?.minWidth || DEFAULT_MIN_WIDTH; + effectColsMinWidth += Math.max( + child.resize?.minWidth || DEFAULT_MIN_WIDTH, + getColWidthAttr(child, 'minWidth') || DEFAULT_MIN_WIDTH + ); }); // 按比例划分新宽度(拖动列) @@ -76,11 +90,15 @@ export default function setThWidthListByColumnDrag>( const remainWidth = Math.max( effectColsMinWidth, oldWidth + oldEffectWidth - dragWidth, - effectCol.resize?.minWidth || DEFAULT_MIN_WIDTH, + Math.max( + getColWidthAttr(effectCol, 'minWidth') || DEFAULT_MIN_WIDTH, + effectCol.resize?.minWidth || DEFAULT_MIN_WIDTH + ), ); effectChildrenCols.forEach((child) => { updateMap[child.colKey] = Math.max( child.resize?.minWidth || DEFAULT_MIN_WIDTH, + getColWidthAttr(child, 'minWidth') || DEFAULT_MIN_WIDTH, (thWidthList[child.colKey] / oldEffectWidth) * remainWidth, ); }); @@ -88,15 +106,14 @@ export default function setThWidthListByColumnDrag>( // 更新各列宽度 callback(updateMap, notCalculateCols); } else { - const colWidth = isNumber(dragCol.width) ? dragCol.width : parseFloat(dragCol.width); - const effectWidth = isNumber(effectCol.width) ? effectCol.width : parseFloat(effectCol.width); - const oldWidth = thWidthList[dragCol.colKey] || colWidth; - const oldEffectWidth = thWidthList[effectCol.colKey] || effectWidth; + const oldWidth = thWidthList[dragCol.colKey] || getColWidthAttr(dragCol, 'width'); + const oldEffectWidth = thWidthList[effectCol.colKey] || getColWidthAttr(effectCol, 'width'); callback({ [dragCol.colKey]: dragWidth, [effectCol.colKey]: Math.max( effectCol.resize?.minWidth || DEFAULT_MIN_WIDTH, + getColWidthAttr(effectCol, 'minWidth') || DEFAULT_MIN_WIDTH, oldWidth + oldEffectWidth - dragWidth, ), }, [dragCol.colKey, effectCol.colKey]); diff --git a/js/table/types.ts b/js/table/types.ts index 915ac32a00..92913012f8 100644 --- a/js/table/types.ts +++ b/js/table/types.ts @@ -2,7 +2,12 @@ export interface BaseTableCol { children?: T[], colKey?: string, resize?: { [attr: string]: any }, - width?: number | string + width?: number | string, + minWidth?: number | string, +} + +export interface ThMap { + [colKey: string]: number } export interface PlainObject { diff --git a/js/table/utils.ts b/js/table/utils.ts index 75c7afff37..4e1a050ef1 100644 --- a/js/table/utils.ts +++ b/js/table/utils.ts @@ -1,4 +1,6 @@ import isFunction from 'lodash/isFunction'; +import isNumber from 'lodash/isNumber'; +import { BaseTableCol } from './types'; export function isRowSelectedDisabled( selectColumn: { [key: string]: any }, @@ -15,3 +17,9 @@ export function isRowSelectedDisabled( } return !!disabled; } + +// 获取列属性 +export function getColWidthAttr>(col: T, attrKey: 'width' | 'minWidth') { + const attr = col[attrKey]; + return isNumber(attr) ? attr : parseFloat(attr); +}