From 54387a81e1c6add77e791af8d849a6518077afd5 Mon Sep 17 00:00:00 2001 From: zhouyun1 Date: Fri, 27 Oct 2023 10:43:47 +0800 Subject: [PATCH] =?UTF-8?q?feat(table):=20resizable=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E4=B8=8B=E8=AE=BE=E7=BD=AE=E6=9C=80=E5=B0=8F=E5=88=97=E5=AE=BD?= =?UTF-8?q?=20(#2639)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/blue-glasses-nail.md | 5 ++ .changeset/silent-lions-yawn.md | 5 ++ packages/ui/table/src/TheadContent.tsx | 11 +++- packages/ui/table/src/hooks/use-col-width.ts | 41 +++++++++------ packages/ui/table/src/use-table.ts | 9 +++- .../table/stories/custom-filter.stories.tsx | 52 ++++++++++++++++++- .../ui/table/stories/resizable.stories.tsx | 52 +++++++++++++++++++ 7 files changed, 153 insertions(+), 22 deletions(-) create mode 100644 .changeset/blue-glasses-nail.md create mode 100644 .changeset/silent-lions-yawn.md diff --git a/.changeset/blue-glasses-nail.md b/.changeset/blue-glasses-nail.md new file mode 100644 index 000000000..65de99932 --- /dev/null +++ b/.changeset/blue-glasses-nail.md @@ -0,0 +1,5 @@ +--- +"@hi-ui/hiui": patch +--- + +Table perf: 优化 resizable 模式下可调整的最小宽度 diff --git a/.changeset/silent-lions-yawn.md b/.changeset/silent-lions-yawn.md new file mode 100644 index 000000000..79cd3a34b --- /dev/null +++ b/.changeset/silent-lions-yawn.md @@ -0,0 +1,5 @@ +--- +"@hi-ui/table": patch +--- + +perf: 优化 resizable 模式下可调整的最小宽度 diff --git a/packages/ui/table/src/TheadContent.tsx b/packages/ui/table/src/TheadContent.tsx index 5fa399a98..1952a9bf6 100644 --- a/packages/ui/table/src/TheadContent.tsx +++ b/packages/ui/table/src/TheadContent.tsx @@ -21,6 +21,7 @@ export const TheadContent = forwardRef onColumnResizable, getStickyColProps, showColMenu, + setHeaderTableElement, } = useTableContext() const activeColumnKeysAction = useCheckState() @@ -30,10 +31,16 @@ export const TheadContent = forwardRef {/* 渲染列 */} {groupedColumns.map((cols, colsIndex) => { return ( - + {cols.map((col, colIndex) => { const { dataKey, title, raw } = col || {} - const titleContent = isFunction(title) ? title(col) : title + let titleContent = isFunction(title) ? title(col) : title + + titleContent = resizable ? ( + {titleContent} + ) : ( + titleContent + ) const cell = ( (null) + const [headerTableElement, setHeaderTableElement] = React.useState( + null + ) /** * 控制列最小可调整宽度 */ const minColWidth = React.useMemo(() => { - if ( - headerTableElement && - headerTableElement.childNodes && - headerTableElement.childNodes[1].childNodes[0] - ) { - const _minColWidth = Array.from( - headerTableElement.childNodes[1].childNodes[0].childNodes - ).map((th) => { - // @ts-ignore - return th.childNodes[0].className === 'hi-table__header__title' - ? // @ts-ignore - th.childNodes[0].offsetWidth - : 0 + if (resizable && headerTableElement) { + const resizableHandlerWidth = 4 + const _minColWidth = Array.from(headerTableElement.childNodes).map((th) => { + const thPaddingLeft = parseFloat( + window.getComputedStyle(th as Element).getPropertyValue('padding-left') + ) + const childNodes = Array.from(th.childNodes) + + return ( + childNodes + .map((child) => (child as HTMLElement).offsetWidth) + .reduce((prev, next) => { + return prev + next + }) + + thPaddingLeft * 2 + + resizableHandlerWidth + ) }) return _minColWidth } + return Array(columns.length).fill(0) - }, [columns, headerTableElement]) + }, [columns.length, headerTableElement, resizable]) /** * 列宽拖拽 resize,只处理拖拽线两边的列宽度 */ const onColumnResizable = React.useCallback( (_, { size }, index: number) => { - const minWidth = minColWidth[index] + 31 - const anotherMinWidth = minColWidth[index + 1] + 31 + const minWidth = minColWidth[index] + const anotherMinWidth = minColWidth[index + 1] let nextWidth = size.width > minWidth ? size.width : minWidth setColWidths((prev) => { diff --git a/packages/ui/table/src/use-table.ts b/packages/ui/table/src/use-table.ts index 1e5f9e6ec..c9ca2d29e 100644 --- a/packages/ui/table/src/use-table.ts +++ b/packages/ui/table/src/use-table.ts @@ -175,7 +175,13 @@ export const useTable = ({ // ************************ 列宽 resizable ************************ // - const { measureRowElementRef, getColgroupProps, onColumnResizable, colWidths } = useColWidth({ + const { + measureRowElementRef, + getColgroupProps, + onColumnResizable, + colWidths, + setHeaderTableElement, + } = useColWidth({ data, columns, resizable, @@ -635,6 +641,7 @@ export const useTable = ({ cellRender, showColMenu, onLoadChildren, + setHeaderTableElement, } } diff --git a/packages/ui/table/stories/custom-filter.stories.tsx b/packages/ui/table/stories/custom-filter.stories.tsx index 56f14a9ce..a5fd228f9 100644 --- a/packages/ui/table/stories/custom-filter.stories.tsx +++ b/packages/ui/table/stories/custom-filter.stories.tsx @@ -4,6 +4,7 @@ import Table from '../src' import Input from '@hi-ui/input' import Button from '@hi-ui/button' import CheckSelect from '@hi-ui/check-select' +import EllipsisTooltip from '@hi-ui/ellipsis-tooltip' /** * @title 自定义过滤 @@ -162,6 +163,9 @@ export const CustomFilter = () => { ) }, + render(text) { + return {text} + }, }, { title: 'Age', @@ -174,7 +178,7 @@ export const CustomFilter = () => { }, { title: ( -
+
Home phone { ), colSpan: 2, width: 180, + render(text) { + return {text} + }, dataKey: 'tel', key: 3, }, @@ -201,18 +208,27 @@ export const CustomFilter = () => { title: 'Home phone1', dataKey: 'tel1', width: 180, + render(text) { + return {text} + }, key: 4, }, { title: 'Home phone2', colSpan: 2, width: 180, + render(text) { + return {text} + }, dataKey: 'tel2', key: 5, }, { title: 'Home phone3', width: 180, + render(text) { + return {text} + }, colSpan: 2, dataKey: 'tel3', key: 6, @@ -220,6 +236,9 @@ export const CustomFilter = () => { { title: 'Home phone4', width: 180, + render(text) { + return {text} + }, colSpan: 2, dataKey: 'tel4', key: 7, @@ -227,6 +246,9 @@ export const CustomFilter = () => { { title: 'Home phone5', width: 180, + render(text) { + return {text} + }, colSpan: 2, dataKey: 'tel5', key: 8, @@ -234,6 +256,9 @@ export const CustomFilter = () => { { title: 'Home phone6', width: 180, + render(text) { + return {text} + }, colSpan: 2, dataKey: 'tel6', key: 9, @@ -241,6 +266,9 @@ export const CustomFilter = () => { { title: 'Home phone7', width: 180, + render(text) { + return {text} + }, colSpan: 2, dataKey: 'tel7', key: 10, @@ -248,6 +276,9 @@ export const CustomFilter = () => { { title: 'Home phone8', width: 180, + render(text) { + return {text} + }, colSpan: 2, dataKey: 'tel8', key: 11, @@ -255,6 +286,9 @@ export const CustomFilter = () => { { title: 'Home phone9', width: 180, + render(text) { + return {text} + }, colSpan: 2, dataKey: 'tel9', key: 12, @@ -262,6 +296,9 @@ export const CustomFilter = () => { { title: 'Home phone10', width: 180, + render(text) { + return {text} + }, colSpan: 2, dataKey: 'tel10', key: 13, @@ -269,6 +306,9 @@ export const CustomFilter = () => { { title: 'Home phone11', width: 180, + render(text) { + return {text} + }, colSpan: 2, dataKey: 'tel11', key: 14, @@ -277,15 +317,20 @@ export const CustomFilter = () => { { title: 'Home phone12', width: 180, + render(text) { + return {text} + }, colSpan: 2, dataKey: 'tel12', key: 15, }, - { title: 'Phone', dataKey: 'phone', width: 180, + render(text) { + return {text} + }, key: 16, sorter(pre, next) { return pre.phone - next.phone @@ -294,6 +339,9 @@ export const CustomFilter = () => { { title: 'Address', width: 240, + render(text) { + return {text} + }, dataKey: 'address', key: 17, }, diff --git a/packages/ui/table/stories/resizable.stories.tsx b/packages/ui/table/stories/resizable.stories.tsx index 1dd38adab..a9be2c14f 100644 --- a/packages/ui/table/stories/resizable.stories.tsx +++ b/packages/ui/table/stories/resizable.stories.tsx @@ -1,5 +1,6 @@ import React from 'react' import Table from '../src' +import EllipsisTooltip from '@hi-ui/ellipsis-tooltip' /** * @title 可调节列宽 @@ -17,6 +18,9 @@ export const Resizable = () => { title: '商品名', dataKey: 'name', width: 120, + render(text) { + return {text} + }, }, { title: '品类', @@ -27,83 +31,131 @@ export const Resizable = () => { title: '规格', dataKey: 'size', width: 150, + render(text) { + return {text} + }, }, { title: '单价', dataKey: 'price', width: 150, + render(text) { + return {text} + }, }, { title: '规格', dataKey: 'size', width: 150, + render(text) { + return {text} + }, }, { title: '单价', dataKey: 'price', width: 150, + render(text) { + return {text} + }, }, { title: '规格', dataKey: 'size', width: 150, + render(text) { + return {text} + }, }, { title: '单价', dataKey: 'price', width: 150, + render(text) { + return {text} + }, }, { title: '规格', dataKey: 'size', width: 150, + render(text) { + return {text} + }, }, { title: '单价', dataKey: 'price', width: 150, + render(text) { + return {text} + }, }, { title: '规格', dataKey: 'size', width: 150, + render(text) { + return {text} + }, }, { title: '单价', dataKey: 'price', width: 150, + render(text) { + return {text} + }, }, { title: '规格', dataKey: 'size', width: 150, + render(text) { + return {text} + }, }, { title: '单价', dataKey: 'price', width: 150, + render(text) { + return {text} + }, }, { title: '规格', dataKey: 'size', width: 150, + render(text) { + return {text} + }, }, { title: '单价', dataKey: 'price', width: 150, + render(text) { + return {text} + }, }, { title: '规格', dataKey: 'size', width: 150, + render(text) { + return {text} + }, }, { title: '单价', dataKey: 'price', width: 150, + render(text) { + return {text} + }, }, { title: '门店',