فهرست منبع

feat:Table column support resize prop (#1770)

* feat: Table column add resize prop #1762

* docs: update Table resize demo

* chore: resolve conflict

---------

Co-authored-by: shijia.me <[email protected]>
Co-authored-by: pointhalo <[email protected]>
Shi Jia 2 سال پیش
والد
کامیت
468d65ff3a

+ 18 - 2
content/show/table/index-en-US.md

@@ -2825,8 +2825,12 @@ But you need to pay attention to some parameters:
 
 -   `resizable` is set to `true` or an `object`
 -   Any column in `columns` that requires a telescopic function should specify the `width`field (if not passed, the column does not have a telescopic function and its column width will be automatically adjusted by the browser)
+-   `column.resize` can take effect after resizable is enabled. After setting to false, the column no longer supports scaling. v2.42 support
 
-> It is not recommended to use with fixed columns at the same time. Fixed columns need to specify `scroll.x`, which stipulates that the table has a width range, and the flexible column will expand the column width, which may cause the table to be misaligned
+
+> When used with fixed columns, you need to specify a column without setting the width
+
+> It is not recommended to use it with `scroll.x` at the same time. scroll.x specifies that the table has a width range, and stretching columns will expand the column width, which may cause the table to be misaligned
 
 ```jsx live=true noInline=true dir="column"
 import React, { useMemo } from 'react';
@@ -2841,7 +2845,8 @@ function ResizableDemo() {
         {
             title: 'Title',
             dataIndex: 'name',
-            width: 400,
+            width: 300,
+            resize: false,
             render: (text, record, index) => {
                 return (
                     <div>
@@ -2892,6 +2897,16 @@ function ResizableDemo() {
                 return dateFns.format(new Date(value), 'yyyy-MM-dd');
             },
         },
+        {
+            title: 'Operate',
+            dataIndex: 'operate',
+            fixed: 'right',
+            width: 100,
+            resize: false,
+            render: () => {
+                return <IconMore />;
+            },
+        },
     ];
 
     const data = useMemo(() => {
@@ -4997,6 +5012,7 @@ import { Table } from '@douyinfe/semi-ui';
 | key | The key required by React, if a unique dataIndex has been set, can ignore this property | string |  |
 | render | A rendering function that generates complex data, the parameters are the value of the current row, the current row data, the row index, and the table row / column merge can be set in return object | (text: any, record: RecordType, index: number, { expandIcon?: ReactNode, selection?: ReactNode, indentText?: ReactNode }) => React\|object |  |
 | renderFilterDropdownItem | Customize the rendering method of each filter item. For usage details, see [Custom Filter Item Rendering](#Custom-Filter-Item-Rendering) | ({ value: any, text: any, onChange: Function, level: number, ...otherProps }) => ReactNode | - | **1.1.0** |
+| resize | Whether to enable resize mode, this property will take effect only after Table resizable is enabled | boolean |  | **2.42.0** |
 | sortChildrenRecord | Whether to sort child data locally | boolean |  | **0.29.0** |
 | sortOrder | The controlled property of the sorting, the sorting of this control column can be set to 'ascend'\|'descended '\|false | boolean | false |
 | sorter | Sorting function, local sorting uses a function (refer to the compreFunction of Array.sort), requiring a server-side sorting can be set to true | boolean\|(r1: RecordType, r2: RecordType) => number | true |

+ 19 - 4
content/show/table/index.md

@@ -2830,10 +2830,13 @@ render(App);
 
 不过你需要注意一些参数:
 
--   `resizable` 设定为 `true` 或者一个 `object`
--   `columns` 里需要伸缩功能的列都要指定 `width` 这个字段(如果不传,该列不具备伸缩功能,且其列宽度会被浏览器自动调整)
+- `resizable` 设定为 `true` 或者一个 `object`
+- `columns` 里需要伸缩功能的列都要指定 `width` 这个字段(如果不传,该列不具备伸缩功能,且其列宽度会被浏览器自动调整)
+- `column.resize` 可以在 resizable 开启后生效,设置为 false 后,列不再支持伸缩。v2.42 支持
 
-> 不推荐与固定列同时使用,固定列需要指定 `scroll.x`,这约定了表格是有宽度范围的,而伸缩列会拓展列宽,这可能会导致表格对不齐
+> 与固定列同时使用时,需指定某一列不设置宽度
+
+> 不推荐与 `scroll.x` 同时使用,scroll.x 指定表格是有宽度范围的,而伸缩列会拓展列宽,这可能会导致表格对不齐
 
 ```jsx live=true noInline=true dir="column"
 import React, { useMemo } from 'react';
@@ -2848,7 +2851,8 @@ function ResizableDemo() {
         {
             title: '标题',
             dataIndex: 'name',
-            width: 400,
+            width: 300,
+            resize: false,
             render: (text, record, index) => {
                 return (
                     <div>
@@ -2899,6 +2903,16 @@ function ResizableDemo() {
                 return dateFns.format(new Date(value), 'yyyy-MM-dd');
             },
         },
+        {
+            title: '操作列',
+            dataIndex: 'operate',
+            fixed: 'right',
+            width: 100,
+            resize: false,
+            render: () => {
+                return <IconMore />;
+            },
+        },
     ];
 
     const data = useMemo(() => {
@@ -5012,6 +5026,7 @@ import { Table } from '@douyinfe/semi-ui';
 | key | React 需要的 key,如果已经设置了唯一的 dataIndex,可以忽略这个属性 | string |  |
 | render | 生成复杂数据的渲染函数,参数分别为当前行的值,当前行数据,行索引,@return 里面可以设置表格行/列合并 | (text: any, record: RecordType, index: number, { expandIcon?: ReactNode, selection?: ReactNode, indentText?: ReactNode }) => object\|ReactNode |  |
 | renderFilterDropdownItem | 自定义每个筛选项渲染方式,用法详见[自定义筛选项渲染](#自定义筛选项渲染) | ({ value: any, text: any, onChange: Function, level: number, ...otherProps }) => ReactNode | - | **1.1.0** |
+| resize | 是否开启 resize 模式,只有 Table resizable 开启后此属性才会生效 | boolean |  | **2.42.0** |
 | sortChildrenRecord | 是否对子级数据进行本地排序 | boolean |  | **0.29.0** |
 | sortOrder | 排序的受控属性,外界可用此控制列的排序,可设置为 'ascend'\|'descend'\|false | boolean\| string | false |
 | sorter | 排序函数,本地排序使用一个函数(参考 Array.sort 的 compareFunction),需要服务端排序可设为 true | boolean\|(r1: RecordType, r2: RecordType) => number | true |

+ 7 - 4
packages/semi-ui/table/ResizableHeaderCell.tsx

@@ -6,14 +6,16 @@ export interface ResizableHeaderCellProps {
     onResize?: ResizeFn;
     onResizeStart?: ResizeFn;
     onResizeStop?: ResizeFn;
-    width?: number | string
+    width?: number | string;
+    /** For compatibility with previous versions, the default value is true. If you don't want to resize, set it to false */
+    resize?: boolean
 }
 
 class ResizableHeaderCell extends React.PureComponent<ResizableHeaderCellProps> {
     render() {
-        const { onResize, onResizeStart, onResizeStop, width, ...restProps } = this.props;
+        const { onResize, onResizeStart, onResizeStop, width, resize, ...restProps } = this.props;
 
-        if (typeof width !== 'number') {
+        if (typeof width !== 'number' || resize === false) {
             return <th {...restProps} />;
         }
 
@@ -24,12 +26,13 @@ class ResizableHeaderCell extends React.PureComponent<ResizableHeaderCellProps>
 
         return (
             <Resizable
-                width={width}
+                width={width as number}
                 height={0}
                 onResize={onResize}
                 onResizeStart={onResizeStart}
                 onResizeStop={onResizeStop}
                 draggableOpts={{ enableUserSelectHack: false }}
+                axis='x'
             >
                 <th {...restProps}>
                     {children}

+ 2 - 2
packages/semi-ui/table/TableHeader.tsx

@@ -6,7 +6,7 @@ import BaseComponent, { BaseProps } from '../_base/baseComponent';
 import { strings, cssClasses } from '@douyinfe/semi-foundation/table/constants';
 import { shouldShowEllipsisTitle } from '@douyinfe/semi-foundation/table/utils';
 import TableHeaderRow from './TableHeaderRow';
-import { Fixed, TableComponents, OnHeaderRow } from './interface';
+import { Fixed, TableComponents, OnHeaderRow, ColumnProps } from './interface';
 
 function parseHeaderRows(columns: any[]) {
     const rows: any[] = [];
@@ -175,7 +175,7 @@ export interface TableHeaderCell {
     key: string | number;
     className: string;
     children: ReactNode;
-    column: any[];
+    column: ColumnProps;
     colStart: number;
     level: number;
     parents: any[];

+ 5 - 2
packages/semi-ui/table/TableHeaderRow.tsx

@@ -16,10 +16,11 @@ import {
 import BaseComponent from '../_base/baseComponent';
 import TableContext, { TableContextProps } from './table-context';
 import { TableComponents, OnHeaderRow, Fixed } from './interface';
+import type { TableHeaderCell } from './TableHeader';
 
 export interface TableHeaderRowProps {
     components?: TableComponents;
-    row?: any[];
+    row?: TableHeaderCell[];
     prefixCls?: string;
     onHeaderRow?: OnHeaderRow<any>;
     index?: number;
@@ -81,7 +82,7 @@ export default class TableHeaderRow extends BaseComponent<TableHeaderRowProps, R
             this.context.setHeadWidths(
                 map(heads, (head, headIndex) => {
                     let configWidth = get(row, [headIndex, 'column', 'width']);
-                    const key = get(row, [headIndex, 'column', 'key']);
+                    const key = get(row, [headIndex, 'column', 'key']) as any;
                     if (typeof configWidth !== 'number') {
                         configWidth = (head && head.getBoundingClientRect().width) || 0;
                     }
@@ -175,6 +176,8 @@ export default class TableHeaderRow extends BaseComponent<TableHeaderRowProps, R
                 }
             }
 
+            Object.assign(cellProps, { resize: column.resize });
+
             const props = omit({ ...cellProps, ...customProps }, [
                 'colStart',
                 'colEnd',

+ 1 - 1
packages/semi-ui/table/_story/table.stories.jsx

@@ -99,7 +99,7 @@ export {
     Fixed1556,
     FixedColumnAlign,
     FixOnChange,
-    FixedSticky
+    ColumnResize
 } from './v2';
 export { default as FixSelectAll325 } from './Demos/rowSelection';
 

+ 104 - 0
packages/semi-ui/table/_story/v2/ColumnResize/index.tsx

@@ -0,0 +1,104 @@
+import React, { useMemo } from 'react';
+import { Table, Avatar } from '@douyinfe/semi-ui';
+import * as dateFns from 'date-fns';
+import { ColumnProps } from '../../../interface';
+import { IconMore } from '@douyinfe/semi-icons';
+
+
+/**
+ * fixed columns with resizable
+ */
+function App() {
+    const DAY = 24 * 60 * 60 * 1000;
+    const figmaIconUrl = 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/figma-icon.png';
+    
+    const columns: ColumnProps[] = [
+        {
+            title: 'fixed + width',
+            dataIndex: 'name',
+            width: 300,
+            render: (text, record, index) => {
+                return (
+                    <div>
+                        <Avatar size="small" shape="square" src={figmaIconUrl} style={{ marginRight: 12 }}></Avatar>
+                        {text}
+                    </div>
+                );
+            },
+            filters: [
+                {
+                    text: 'Semi Design 设计稿',
+                    value: 'Semi Design 设计稿',
+                },
+                {
+                    text: 'Semi D2C 设计稿',
+                    value: 'Semi D2C 设计稿',
+                },
+            ],
+            fixed: true,
+            resize: false,
+            onFilter: (value, record) => record.name.includes(value),
+        },
+        {
+            title: '有固定宽度',
+            dataIndex: 'size',
+            width: 200,
+            sorter: (a, b) => (a.size - b.size > 0 ? 1 : -1),
+            render: text => `${text} KB`,
+        },
+        {
+            title: '有固定宽度',
+            width: 200,
+            dataIndex: 'owner',
+            render: (text, record, index) => {
+                return (
+                    <div>
+                        <Avatar size="small" color={record.avatarBg} style={{ marginRight: 4 }}>
+                            {typeof text === 'string' && text.slice(0, 1)}
+                        </Avatar>
+                        {text}
+                    </div>
+                );
+            },
+        },
+        {
+            title: '留一列自适应宽度',
+            dataIndex: 'updateTime',
+            sorter: (a, b) => (a.updateTime - b.updateTime > 0 ? 1 : -1),
+            render: value => {
+                return dateFns.format(new Date(value), 'yyyy-MM-dd');
+            },
+        },
+        {
+            title: 'fixed + width',
+            dataIndex: 'operate',
+            fixed: 'right',
+            width: 200,
+            resize: false,
+            render: () => {
+                return <IconMore />;
+            },
+        },
+    ];
+
+    const data = useMemo(() => {
+        const _data = [];
+        for (let i = 0; i < 46; i++) {
+            const isSemiDesign = i % 2 === 0;
+            const randomNumber = (i * 1000) % 199;
+            _data.push({
+                key: '' + i,
+                name: isSemiDesign ? `Semi Design 设计稿${i}.fig` : `Semi D2C 设计稿${i}.fig`,
+                owner: isSemiDesign ? '姜鹏志' : '郝宣',
+                size: randomNumber,
+                updateTime: new Date().valueOf() + randomNumber * DAY,
+                avatarBg: isSemiDesign ? 'grey' : 'red',
+            });
+        }
+        return _data;
+    }, []);
+
+    return <Table columns={columns} dataSource={data} resizable bordered />;
+}
+
+export default App;

+ 1 - 1
packages/semi-ui/table/_story/v2/index.js

@@ -20,4 +20,4 @@ export { EllipsisNormalTable, EllipsisFixedTable, ShowTitleTable } from './FeatE
 export { default as Fixed1556 } from './Fixed1556';
 export { default as FixedColumnAlign } from './FixedColumnAlign';
 export { default as FixOnChange } from './FixOnChange';
-export { default as FixedSticky } from './FixedSticky';
+export { default as ColumnResize } from './ColumnResize';

+ 3 - 2
packages/semi-ui/table/interface.ts

@@ -105,7 +105,8 @@ export interface ColumnProps<RecordType extends Record<string, any> = any> {
     onFilter?: OnFilter<RecordType>;
     onFilterDropdownVisibleChange?: OnFilterDropdownVisibleChange;
     onHeaderCell?: OnHeaderCell<RecordType>;
-    ellipsis?: BaseEllipsis
+    ellipsis?: BaseEllipsis;
+    resize?: boolean
 }
 
 export type Align = BaseAlign;
@@ -120,7 +121,7 @@ export type Fixed = BaseFixed;
 export type OnCell<RecordType> = (record?: RecordType, rowIndex?: number) => OnCellReturnObject;
 export type OnFilter<RecordType> = (filteredValue?: any, record?: RecordType) => boolean;
 export type OnFilterDropdownVisibleChange = (visible?: boolean) => void;
-export type OnHeaderCell<RecordType> = (record?: RecordType, columnIndex?: number) => OnHeaderCellReturnObject;
+export type OnHeaderCell<RecordType> = (record?: RecordType, columnIndex?: number, index?: number) => OnHeaderCellReturnObject;
 export type ColumnRender<RecordType> = (text: any, record: RecordType, index: number, options?: RenderOptions) => ColumnRenderReturnType;
 export type RenderFilterDropdownItem = (itemInfo?: FilterDropdownItem) => ReactNode;
 export type Sorter<RecordType> = BaseSorter<RecordType>;