From db93b9a68e0f200f61ec0ed27db35e63a6337cec Mon Sep 17 00:00:00 2001 From: ZTao-z <1124693098@qq.com> Date: Mon, 29 Aug 2022 18:03:18 +0800 Subject: [PATCH] =?UTF-8?q?fix(table):=20=E5=A4=9A=E7=BA=A7=E8=A1=A8?= =?UTF-8?q?=E5=A4=B4=E6=94=AF=E6=8C=81=E8=B0=83=E6=95=B4=E5=88=97=E5=AE=BD?= =?UTF-8?q?=20(#1395)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(table): multiple header resize * fix(table): update demo * fix(table): update test case * fix(table): extract public functions * fix(table): update import * fix(table): update _common * fix(table): optimize code * fix(table): remove useless code --- .../__tests__/__snapshots__/demo.test.js.snap | 2 +- src/table/_example/multi-header.vue | 2 + src/table/base-table.tsx | 14 +- src/table/hooks/useColumnResize.ts | 184 ++++++------------ src/table/thead.tsx | 14 +- test/ssr/__snapshots__/ssr.test.js.snap | 2 +- 6 files changed, 74 insertions(+), 144 deletions(-) diff --git a/src/table/__tests__/__snapshots__/demo.test.js.snap b/src/table/__tests__/__snapshots__/demo.test.js.snap index 9cce519d1..0062ca3c9 100644 --- a/src/table/__tests__/__snapshots__/demo.test.js.snap +++ b/src/table/__tests__/__snapshots__/demo.test.js.snap @@ -17777,7 +17777,7 @@ exports[`Table Table multiHeaderVue demo works fine 1`] = `
[ @@ -157,6 +159,16 @@ export default defineComponent({ { immediate: true }, ); + watch( + thList, + () => { + setEffectColMap(thList.value[0], null); + }, + { + immediate: true, + }, + ); + const onFixedChange = () => { nextTick(() => { onHorizontalScroll(); diff --git a/src/table/hooks/useColumnResize.ts b/src/table/hooks/useColumnResize.ts index c767d6759..8218da031 100644 --- a/src/table/hooks/useColumnResize.ts +++ b/src/table/hooks/useColumnResize.ts @@ -1,7 +1,8 @@ import { ref, Ref, reactive } from '@vue/composition-api'; -import isNumber from 'lodash/isNumber'; import { RecalculateColumnWidthFunc } from '../interface'; import { BaseTableCol, TableRowData } from '../type'; +import setThWidthListByColumnDrag from '../../_common/js/table/set-column-width-by-drag'; +import recalculateColumnWidth from '../../_common/js/table/recalculate-column-width'; const DEFAULT_MIN_WIDTH = 80; const DEFAULT_MAX_WIDTH = 600; @@ -14,6 +15,23 @@ export default function useColumnResize( ) { const resizeLineRef = ref(); const notCalculateWidthCols = ref([]); + const effectColMap = ref<{ [colKey: string]: any }>({}); + + // 递归查找列宽度变化后,受影响的相关列 + const setEffectColMap = (nodes: BaseTableCol[], parent: BaseTableCol | null) => { + if (!nodes) return; + nodes.forEach((n, index) => { + const parentPrevCol = parent ? effectColMap.value[parent.colKey].prev : nodes[index + 1]; + const parentNextCol = parent ? effectColMap.value[parent.colKey].next : nodes[index - 1]; + const prev = index === 0 ? parentPrevCol : nodes[index - 1]; + const next = index === nodes.length - 1 ? parentNextCol : nodes[index + 1]; + effectColMap.value[n.colKey] = { + prev, + next, + }; + setEffectColMap(n.children, n); + }); + }; const resizeLineParams = { isDragging: false, @@ -67,12 +85,7 @@ export default function useColumnResize( }; // 调整表格列宽 - const onColumnMousedown = ( - e: MouseEvent, - col: BaseTableCol, - effectNextCol: BaseTableCol, - effectPrevCol: BaseTableCol, - ) => { + const onColumnMousedown = (e: MouseEvent, col: BaseTableCol) => { // 非 resize 的点击,不做处理 if (!resizeLineParams.draggingCol) return; @@ -86,6 +99,9 @@ export default function useColumnResize( const minResizeLineLeft = colLeft + minColWidth; const maxResizeLineLeft = colLeft + maxColWidth; + const effectNextCol = effectColMap.value[col.colKey].next; + const effectPrevCol = effectColMap.value[col.colKey].prev; + // 开始拖拽,记录下鼠标起始位置 resizeLineParams.isDragging = true; resizeLineParams.draggingStart = e.x; @@ -99,26 +115,6 @@ export default function useColumnResize( resizeLineStyle.bottom = `${parent.bottom - tableBoundRect.bottom}px`; } - const setThWidthListByColumnDrag = ( - dragCol: BaseTableCol, - dragWidth: number, - nearCol: BaseTableCol, - ) => { - const thWidthList = getThWidthList(); - - const propColWidth = isNumber(dragCol.width) ? dragCol.width : parseFloat(dragCol.width); - const propNearColWidth = isNumber(nearCol.width) ? nearCol.width : parseFloat(nearCol.width); - const oldWidth = thWidthList[dragCol.colKey] || propColWidth; - const oldNearWidth = thWidthList[nearCol.colKey] || propNearColWidth; - - updateThWidthList({ - [dragCol.colKey]: dragWidth, - [nearCol.colKey]: Math.max(nearCol.resize?.minWidth || DEFAULT_MIN_WIDTH, oldWidth + oldNearWidth - dragWidth), - }); - - setNotCalculateWidthCols([dragCol.colKey, nearCol.colKey]); - }; - // 拖拽时鼠标可能会超出 table 范围,需要给 document 绑定拖拽相关事件 const onDragEnd = () => { if (resizeLineParams.isDragging) { @@ -132,9 +128,27 @@ export default function useColumnResize( } // 更新列宽 if (resizeLineParams.effectCol === 'next') { - setThWidthListByColumnDrag(col, width, effectNextCol); + setThWidthListByColumnDrag>( + col, + width, + effectNextCol, + { getThWidthList, DEFAULT_MIN_WIDTH }, + (updateMap, notCalculateCols) => { + updateThWidthList(updateMap); + setNotCalculateWidthCols(notCalculateCols); + }, + ); } else if (resizeLineParams.effectCol === 'prev') { - setThWidthListByColumnDrag(effectPrevCol, width, col); + setThWidthListByColumnDrag>( + effectPrevCol, + width, + col, + { getThWidthList, DEFAULT_MIN_WIDTH }, + (updateMap, notCalculateCols) => { + updateThWidthList(updateMap); + setNotCalculateWidthCols(notCalculateCols); + }, + ); } // 恢复设置 @@ -175,108 +189,19 @@ export default function useColumnResize( tableLayout: string, tableElmWidth: number, ): void => { - let actualWidth = 0; - const missingWidthCols: BaseTableCol[] = []; - const thMap: { [colKey: string]: number } = {}; - - // 计算现有列的列宽总和 - columns.forEach((col) => { - if (!thWidthList[col.colKey]) { - thMap[col.colKey] = isNumber(col.width) ? col.width : parseFloat(col.width); - } else { - thMap[col.colKey] = thWidthList[col.colKey]; - } - const originWidth = thMap[col.colKey]; - if (originWidth) { - actualWidth += originWidth; - } else { - missingWidthCols.push(col); - } - }); - - let tableWidth = tableElmWidth; - let needUpdate = false; - // 表宽没有初始化时,默认给没有指定列宽的列指定宽度为100px - 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; - } - }); - } - needUpdate = true; - } else { - // 所有列都已经指定宽度 + recalculateColumnWidth>( + columns, + thWidthList, + tableLayout, + tableElmWidth, + notCalculateWidthCols.value, + (widthMap) => { + updateThWidthList(widthMap); if (notCalculateWidthCols.value.length) { - // 存在不允许重新计算宽度的列(一般是resize后的两列),这些列不参与后续计算 - let sum = 0; - notCalculateWidthCols.value.forEach((colKey) => { - sum += thMap[colKey]; - }); - actualWidth -= sum; - tableWidth -= sum; - } - // 重新计算其他列的宽度,按表格剩余宽度进行按比例分配 - if (actualWidth !== tableWidth || notCalculateWidthCols.value.length) { - columns.forEach((col) => { - if (notCalculateWidthCols.value.includes(col.colKey)) return; - thMap[col.colKey] = (thMap[col.colKey] / actualWidth) * tableWidth; - }); - needUpdate = true; - } - } - } else { - // 表格宽度未初始化,默认填充100px - missingWidthCols.forEach((col) => { - const originWidth = thMap[col.colKey] || 100; - thMap[col.colKey] = isNumber(originWidth) ? originWidth : parseFloat(originWidth); - }); - - needUpdate = true; - } - - // 列宽转为整数 - if (needUpdate) { - let addon = 0; - Object.keys(thMap).forEach((key) => { - const width = thMap[key]; - addon += width - Math.floor(width); - thMap[key] = Math.floor(width) + (addon > 1 ? 1 : 0); - if (addon > 1) { - addon -= 1; + notCalculateWidthCols.value = []; } - }); - if (addon > 0.5) { - thMap[columns[0].colKey] += 1; - } - } - - updateThWidthList(thMap); - - if (notCalculateWidthCols.value.length) { - notCalculateWidthCols.value = []; - } + }, + ); }; return { @@ -285,5 +210,6 @@ export default function useColumnResize( onColumnMouseover, onColumnMousedown, recalculateColWidth, + setEffectColMap, }; } diff --git a/src/table/thead.tsx b/src/table/thead.tsx index f515e9b97..2fa3c4a22 100644 --- a/src/table/thead.tsx +++ b/src/table/thead.tsx @@ -29,12 +29,7 @@ export interface TheadProps { resizeLineRef: HTMLDivElement; resizeLineStyle: Object; onColumnMouseover: (e: MouseEvent) => void; - onColumnMousedown: ( - e: MouseEvent, - col: BaseTableCol, - effectNextCol: BaseTableCol, - effectPrevCol: BaseTableCol, - ) => void; + onColumnMousedown: (e: MouseEvent, col: BaseTableCol) => void; }; resizable: Boolean; } @@ -119,12 +114,7 @@ export default defineComponent({ const innerTh = renderTitle(h, this.slots, col, index); const resizeColumnListener = this.resizable ? { - mousedown: (e: MouseEvent) => this.columnResizeParams?.onColumnMousedown?.( - e, - col, - index < row.length - 1 ? row[index + 1] : row[index - 1], - index > 0 ? row[index - 1] : row[index + 1], - ), + mousedown: (e: MouseEvent) => this.columnResizeParams?.onColumnMousedown?.(e, col), mousemove: (e: MouseEvent) => this.columnResizeParams?.onColumnMouseover?.(e), } : {}; diff --git a/test/ssr/__snapshots__/ssr.test.js.snap b/test/ssr/__snapshots__/ssr.test.js.snap index 7e6b6da78..364da45a9 100644 --- a/test/ssr/__snapshots__/ssr.test.js.snap +++ b/test/ssr/__snapshots__/ssr.test.js.snap @@ -17771,7 +17771,7 @@ exports[`ssr snapshot test renders ./src/table/_example/merge-cells.vue correctl exports[`ssr snapshot test renders ./src/table/_example/multi-header.vue correctly 1`] = `
-
+