From a196114661444e7afad152b681da48a5dc7d62f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Wed, 16 Mar 2022 22:19:47 +0800 Subject: [PATCH 01/19] =?UTF-8?q?feat(Table):=20Table=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=A0=91=E5=BD=A2=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=E5=8A=9F=E8=83=BD=20#539?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/README.md | 83 ++++++++++++ packages/react-table/src/TableTr.tsx | 109 +++++++++++++++ packages/react-table/src/index.tsx | 158 ++++++++++------------ packages/react-table/src/style/index.less | 4 + 4 files changed, 269 insertions(+), 85 deletions(-) create mode 100644 packages/react-table/src/TableTr.tsx diff --git a/packages/react-table/README.md b/packages/react-table/README.md index 1c7ed51b03..fd12557402 100644 --- a/packages/react-table/README.md +++ b/packages/react-table/README.md @@ -724,6 +724,87 @@ const Demo = () => ( ReactDOM.render(, _mount_); ``` +### 树形数据展示 + +表格支持树形数据的展示,当数据中有 children 字段时会自动展示为树形表格,如果不需要或配置为其他字段可以用 childrenColumnName 进行配置。 + +可以通过设置 indentSize 以控制每一层的缩进宽度 + +> ⚠️ 注意: 树形数据展示和`expandable.expandedRowRender`请不要同时出现,后续或将支持 + + + +```jsx +import ReactDOM from 'react-dom'; +import React from 'react'; +import { Table, Button, Icon } from 'uiw'; + +const columns = [ + { + title: '姓名', + ellipsis: true, + key: 'name', + }, + { + title: '年龄', + style: { color: 'red' }, + key: 'age', + }, + { + title: '操作', + key: 'edit', + width: 98, + render: (text, key, rowData, rowNumber, columnNumber) => ( +
+ + +
+ ), + }, +]; +const dataSource = [ + { + name: '邓紫棋', + age: '10', + id: '1', + children: [ + { + name: '邓紫棋-0-1', + age: '10', + id: '1-1', + children: [ + { name: '邓紫棋-0-1-1', age: '10', id: '1-1-1',}, + { name: '邓紫棋-0-1-2', age: '10', id: '1-1-2',} + ] + }, + {name: '邓紫棋-0-2', age: '10', id: '1-1'}, + {name: '邓紫棋-0-3', age: '10', id: '1-1'}, + ] + }, + { name: '李易峰', age: '32', id: '2',}, + { name: '范冰冰', age: '23', id: '3', + children: [ + {name: '范冰冰0-1', age: '23', id: '3-1'}, + {name: '范冰冰0-2', age: '23', id: '3-2'}, + {name: '范冰冰0-3', age: '23', id: '3-3'}, + ] + }, +]; +const Demo = () => { + const [expandedRowKeys, setExpandedRowKeys] = React.useState([]) + return ( +
+ + + ) +}; +ReactDOM.render(, _mount_); +``` + ## Props ### Table @@ -768,3 +849,5 @@ ReactDOM.render(, _mount_); | expandedRowKeys | 控制展开的行 rowKey数组 | Array | - | | onExpandedRowsChange | 展开的行变化触发 | (expandedRows)=>void | - | | onExpand | 点击展开图标触发 | (expanded,record,index)=>void | - | +| indentSize | 控制树形结构每一层的缩进宽度 | number | 16 | +| childrenColumnName | 指定树形结构的列名 | string | children | diff --git a/packages/react-table/src/TableTr.tsx b/packages/react-table/src/TableTr.tsx new file mode 100644 index 0000000000..0e32bece77 --- /dev/null +++ b/packages/react-table/src/TableTr.tsx @@ -0,0 +1,109 @@ +import React, { useMemo, useState } from 'react'; +import Icon from '@uiw/react-icon'; +import { TableProps } from './'; +import './style/index.less'; +import { noop } from '@uiw/utils'; + +interface TableTrProps { + rowKey?: keyof T; + data: T[]; + keys: string[]; + render: { [key: string]: any }; + ellipsis?: Record; + prefixCls: string; + onCell: TableProps['onCell']; + isExpandedDom: (record: T, index: number) => false | JSX.Element; + // 控制树形结构每一层的缩进宽度 + indentSize: number; + // 层级 + hierarchy: number; + childrenColumnName: string; +} + +export default function TableTr(props: TableTrProps) { + const { + rowKey, + data, + keys, + render, + ellipsis, + prefixCls, + onCell = noop, + isExpandedDom, + hierarchy, + indentSize, + childrenColumnName, + } = props; + + const [expandIndex, setExpandIndex] = useState>([]); + + const IconDom = useMemo(() => { + return (key: T[keyof T] | number, isOpacity: boolean) => { + const flag = expandIndex.includes(key); + return ( + { + setExpandIndex(flag ? expandIndex.filter((it) => it !== key) : [...expandIndex, key]); + }} + /> + ); + }; + }, [expandIndex]); + if (!Array.isArray(data) || !data.length) { + return null; + } + return ( + + {data.map((trData, rowNum) => { + const key = rowKey ? trData[rowKey] : rowNum; + return ( + + + {keys.map((keyName, colNum) => { + let objs: React.TdHTMLAttributes = { + children: trData[keyName], + }; + if (render[keyName]) { + const child = render[keyName](trData[keyName], keyName, trData, rowNum, colNum); + if (React.isValidElement(child)) { + objs.children = child; + } else { + if (child.props) { + objs = { ...child.props, children: objs.children }; + if (child.props.rowSpan === 0 || child.props.colSpan === 0) return null; + } + if (child.children) { + objs.children = child.children; + } + } + } + if (ellipsis && ellipsis[keyName]) { + objs.className = `${prefixCls}-ellipsis`; + } + const isHasChildren = Array.isArray(trData[childrenColumnName]); + if (colNum === 0 && (hierarchy || isHasChildren)) { + objs.className = `${objs.className} ${prefixCls}-has-children`; + objs.children = ( + <> + {IconDom(key, isHasChildren)} + {objs.children} + + ); + } + return ( + + {expandIndex.includes(key) && ( + + )} + {isExpandedDom(trData, rowNum)} + + ); + })} + + ); +} diff --git a/packages/react-table/src/index.tsx b/packages/react-table/src/index.tsx index 63a418845f..9ca34ca989 100644 --- a/packages/react-table/src/index.tsx +++ b/packages/react-table/src/index.tsx @@ -4,6 +4,7 @@ import Icon from '@uiw/react-icon'; import Thead from './Thead'; import { getLevelItems, getAllColumnsKeys } from './util'; import ExpandableComponent from './Expandable'; +import TableTr from './TableTr'; import './style/index.less'; // 展开配置 @@ -16,14 +17,18 @@ export interface ExpandableType { rowExpandable?: (record: T) => boolean; // 初始时,是否展开所有行 defaultExpandAllRows?: boolean; - // 默认展开的行 rowKey数组 + // 默认展开的行 rowKey数组 defaultExpandedRowKeys?: Array; - // 控制展开的行 rowKey数组 + // 控制展开的行 rowKey数组 expandedRowKeys?: Array; // 展开的行变化触发 onExpandedRowsChange?: (expandedRows: Array) => void; // 点击展开图标触发 onExpand?: (expanded: boolean, record: T, index: number) => void; + // 控制树形结构每一层的缩进宽度 + indentSize?: number; + // 指定树形结构的列名 + childrenColumnName?: string; } export type TableColumns = { @@ -127,54 +132,62 @@ export default function Table(props: TablePro ); }; }, [expandable, expandIndex]); - let keys = getAllColumnsKeys(columns); - let selfColumns: TableColumns[] = []; - if (expandable?.expandedRowRender) { - keys = ['uiw-expanded', ...keys]; - selfColumns = [ - { - title: '', - key: 'uiw-expanded', - width: 50, - align: 'center', - render: (text, key, record, index) => { - return ( - { - expandable.onExpand?.(expand, record, index); - if (expand) { - const result = expandIndex.filter((it) => (rowKey ? it !== record[rowKey] : it !== index)); - expandable.onExpandedRowsChange ? expandable.onExpandedRowsChange(result) : setExpandIndex(result); - } else { - const result = [...expandIndex, rowKey ? record[rowKey] : index]; - expandable.onExpandedRowsChange ? expandable.onExpandedRowsChange(result) : setExpandIndex(result); - } - }} - expandIcon={(expand) => { - if (expandable.rowExpandable && !expandable.rowExpandable?.(record)) { - return null; - } - if (expandable.expandIcon) { - return expandable.expandIcon(expand, record, index); + + const self = useMemo(() => { + let keys = getAllColumnsKeys(columns); + let selfColumns: TableColumns[] = []; + if (expandable?.expandedRowRender) { + keys = ['uiw-expanded', ...keys]; + selfColumns = [ + { + title: '', + key: 'uiw-expanded', + width: 50, + align: 'center', + render: (text, key, record, index) => { + return ( + : ; - }} - /> - ); + onClick={(expand) => { + expandable.onExpand?.(expand, record, index); + if (expand) { + const result = expandIndex.filter((it) => (rowKey ? it !== record[rowKey] : it !== index)); + expandable.onExpandedRowsChange ? expandable.onExpandedRowsChange(result) : setExpandIndex(result); + } else { + const result = [...expandIndex, rowKey ? record[rowKey] : index]; + expandable.onExpandedRowsChange ? expandable.onExpandedRowsChange(result) : setExpandIndex(result); + } + }} + expandIcon={(expand) => { + if (expandable.rowExpandable && !expandable.rowExpandable?.(record)) { + return null; + } + if (expandable.expandIcon) { + return expandable.expandIcon(expand, record, index); + } + return expand ? : ; + }} + /> + ); + }, }, - }, - ...columns, - ]; - } else { - selfColumns = [...columns]; - } + ...columns, + ]; + } else { + selfColumns = [...columns]; + } + return { + keys, + selfColumns, + }; + }, [columns, expandIndex]); + const cls = [prefixCls, className, bordered ? `${prefixCls}-bordered` : null].filter(Boolean).join(' ').trim(); - const { header, render, ellipsis } = getLevelItems(selfColumns); + const { header, render, ellipsis } = getLevelItems(self.selfColumns); return (
@@ -184,44 +197,19 @@ export default function Table(props: TablePro {columns && columns.length > 0 &&
} {data && data.length > 0 && ( - {data.map((trData, rowNum) => { - return ( - - - {keys.map((keyName, colNum) => { - let objs: React.TdHTMLAttributes = { - children: trData[keyName], - }; - if (render[keyName]) { - const child = render[keyName](trData[keyName], keyName, trData, rowNum, colNum); - if (React.isValidElement(child)) { - objs.children = child; - } else { - if (child.props) { - objs = { ...child.props, children: objs.children }; - if (child.props.rowSpan === 0 || child.props.colSpan === 0) return null; - } - if (child.children) { - objs.children = child.children; - } - } - } - if (ellipsis && ellipsis[keyName]) { - objs.className = `${prefixCls}-ellipsis`; - } - return ( - - {isExpandedDom(trData, rowNum)} - - ); - })} + )} {data && data.length === 0 && empty && ( diff --git a/packages/react-table/src/style/index.less b/packages/react-table/src/style/index.less index 148b44a12e..d2952a6495 100644 --- a/packages/react-table/src/style/index.less +++ b/packages/react-table/src/style/index.less @@ -48,6 +48,10 @@ text-overflow: ellipsis; word-break: keep-all; } + &-has-children { + display: flex; + align-items: center; + } &-bordered { > table { tr > th, From 8a0608220248beb1b15cb46b03e835d1590cf2ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Fri, 18 Mar 2022 11:59:45 +0800 Subject: [PATCH 02/19] =?UTF-8?q?feat(Table):=20Table=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=20scroll=20=E5=B1=9E=E6=80=A7=EF=BC=8C=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E5=86=97=E4=BD=99=20div=20#687?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/README.md | 62 +++++++++++++++++++++++++++- packages/react-table/src/TableTr.tsx | 4 +- packages/react-table/src/aaa.tsx | 42 +++++++++++++++++++ packages/react-table/src/index.tsx | 31 +++++++++++--- 4 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 packages/react-table/src/aaa.tsx diff --git a/packages/react-table/README.md b/packages/react-table/README.md index 9e2dab1954..f964c3b2de 100644 --- a/packages/react-table/README.md +++ b/packages/react-table/README.md @@ -65,7 +65,6 @@ const Demo = () => ( ); ReactDOM.render(, _mount_); ``` - ### 表头分组 表头分组通过 `columns` 数组中对象的 `children` 来实现,以渲染分组表头。。 @@ -814,6 +813,66 @@ const Demo = () => { ReactDOM.render(, _mount_); ``` +### 表格列过宽导致 footer 滑动出表格底部 + +使用 scroll 属性给表格设置宽或高即可 + + +```jsx +import ReactDOM from 'react-dom'; +import { Table, Button } from 'uiw'; + +const columns = [ + { + // title: '姓名', + ellipsis: true, + width: 1000, + title: ({ key }) => { + return ( + 字段: {key} + ) + }, + key: 'name', + }, { + title: '年龄', + style: { color: 'red' }, + key: 'age', + }, { + title: '地址', + key: 'info', + }, { + title: '操作', + key: 'edit', + width: 98, + render: (text, key, rowData, rowNumber, columnNumber) => ( +
+ + +
+ ), + }, +]; +const dataSource = [ + { name: '邓紫棋', age: '12', info: '又名G.E.M.,原名邓诗颖,1991年8月16日生于中国上海,中国香港创作型女歌手。', edit: '' }, + { name: '李易峰', age: '32', info: '1987年5月4日出生于四川成都,中国内地男演员、流行乐歌手、影视制片人', edit: '' }, + { name: '范冰冰', age: '23', info: '1981年9月16日出生于山东青岛,中国影视女演员、制片人、流行乐女歌手', edit: '' }, + { name: '杨幂', age: '34', info: '1986年9月12日出生于北京市,中国内地影视女演员、流行乐歌手、影视制片人。', edit: '' }, + { name: 'Angelababy', age: '54', info: '1989年2月28日出生于上海市,华语影视女演员、时尚模特。', edit: '' }, + { name: '唐嫣', age: '12', info: '1983年12月6日出生于上海市,毕业于中央戏剧学院表演系本科班', edit: '' }, + { name: '吴亦凡', age: '4', info: '1990年11月06日出生于广东省广州市,华语影视男演员、流行乐歌手。', edit: '' }, +]; +const Demo = () => ( +
+
onCell(trData, { rowNum, colNum, keyName }, evn)} /> + ); + })} +
onCell(trData, { rowNum, colNum, keyName }, evn)} - /> - ); - })} -
这个是footer} + columns={columns} data={dataSource} + /> + +); +ReactDOM.render(, _mount_); +``` + ## Props ### Table @@ -845,6 +904,7 @@ ReactDOM.render(, _mount_); | render | 生成复杂数据的渲染函数,参数分别为当前行的值,当前值的 `key`,行索引数据,当前行号,当前列号。| `Function(text, key, rowData, rowNumber, columnNumber)` | - | | align | 设置列的对齐方式 | "left"|"center"|"right" | - | | className | 列样式类名 | string | - | +| scroll | 表格是否可滚动,也可以指定滚动区域的宽、高 | { x?: React.CSSProperties['width'], y?: React.CSSProperties['height'] } | - | ### expandable diff --git a/packages/react-table/src/TableTr.tsx b/packages/react-table/src/TableTr.tsx index 2b09e74c04..884f3ec0a2 100644 --- a/packages/react-table/src/TableTr.tsx +++ b/packages/react-table/src/TableTr.tsx @@ -75,7 +75,7 @@ export default function TableTr(props: TableTr children: trData[keyName.key!], }; if (render[keyName.key!]) { - const child = render[keyName.key!](trData[keyName.key!], keyName.key!, trData, rowNum, colNum); + const child = render[keyName.key!](trData[keyName.key!], keyName.key, trData, rowNum, colNum); if (React.isValidElement(child)) { objs.children = child; } else { @@ -106,7 +106,7 @@ export default function TableTr(props: TableTr {...objs} key={colNum} // style={keyName?.style} - className={`${objs.className} ${prefixCls}-tr-children-${keyName?.align || 'left'} ${ + className={`${objs.className || ''} ${prefixCls}-tr-children-${keyName.align || 'left'} ${ keyName.className || '' }`} onClick={(evn) => onCell(trData, { rowNum, colNum, keyName: keyName.key! }, evn)} diff --git a/packages/react-table/src/aaa.tsx b/packages/react-table/src/aaa.tsx new file mode 100644 index 0000000000..d03ad13ad4 --- /dev/null +++ b/packages/react-table/src/aaa.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Table, Button } from '../../uiw'; + +const columns = [ + { + // title: '姓名', + width: 90008, + ellipsis: true, + // title: ({ key }) => { + // return ( + // 字段: {key} + // ) + // }, + key: 'name', + }, + { + title: '年龄', + style: { color: 'red' }, + width: 100, + key: 'age', + }, +]; +const dataSource = [ + { + name: '邓紫棋', + age: '12', + info: '又名G.E.M.,原名邓诗颖,1991年8月16日生于中国上海,中国香港创作型女歌手。', + edit: '', + }, + { name: '李易峰', age: '32', info: '1987年5月4日出生于四川成都,中国内地男演员、流行乐歌手、影视制片人', edit: '' }, +]; +const Demo = () => ( +
+
} + /> + +); diff --git a/packages/react-table/src/index.tsx b/packages/react-table/src/index.tsx index 76854026ab..1beef63205 100644 --- a/packages/react-table/src/index.tsx +++ b/packages/react-table/src/index.tsx @@ -66,6 +66,7 @@ export interface TableProps exten ) => void; expandable?: ExpandableType; rowKey?: keyof T; + scroll?: { x?: React.CSSProperties['width']; y?: React.CSSProperties['height'] }; } export interface ICellOptions { @@ -88,6 +89,7 @@ export default function Table(props: TablePro children, expandable, rowKey, + scroll, ...other } = props; const [expandIndex, setExpandIndex] = useState>([]); @@ -187,14 +189,31 @@ export default function Table(props: TablePro selfColumns, }; }, [columns, expandIndex]); - + const style: { table: React.CSSProperties; div: React.CSSProperties } = useMemo(() => { + const style: { table: React.CSSProperties; div: React.CSSProperties } = { + table: {}, + div: {}, + }; + if (scroll) { + if (scroll.x !== undefined) { + style.table.minWidth = '100%'; + style.table.width = scroll.x; + style.div.overflowX = 'auto'; + style.div.overflowY = 'hidden'; + } + if (scroll.y !== undefined) { + style.div.maxHeight = scroll.y; + style.div.overflowY = 'scroll'; + } + } + return style; + }, [scroll]); const cls = [prefixCls, className, bordered ? `${prefixCls}-bordered` : null].filter(Boolean).join(' ').trim(); const { header, render, ellipsis } = getLevelItems(self.selfColumns); - return ( -
-
-
+ +
+
{title && } {columns && columns.length > 0 && } {data && data.length > 0 && ( @@ -227,6 +246,6 @@ export default function Table(props: TablePro
{title}
{footer &&
{footer}
} - + ); } From a11db86a21df29b129f0f026fa4f46f9dfd460fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Fri, 18 Mar 2022 12:02:11 +0800 Subject: [PATCH 03/19] =?UTF-8?q?feat(Table):=20Table=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=20scroll=20=E5=B1=9E=E6=80=A7=EF=BC=8C=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E5=86=97=E4=BD=99=20div=20#687?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/README.md | 2 +- packages/react-table/src/aaa.tsx | 42 -------------------------------- 2 files changed, 1 insertion(+), 43 deletions(-) delete mode 100644 packages/react-table/src/aaa.tsx diff --git a/packages/react-table/README.md b/packages/react-table/README.md index f964c3b2de..d9c45704d7 100644 --- a/packages/react-table/README.md +++ b/packages/react-table/README.md @@ -815,7 +815,7 @@ ReactDOM.render(, _mount_); ### 表格列过宽导致 footer 滑动出表格底部 -使用 scroll 属性给表格设置宽或高即可 +使用 scroll 属性给表格设置宽(x)或高(y)即可 ```jsx diff --git a/packages/react-table/src/aaa.tsx b/packages/react-table/src/aaa.tsx deleted file mode 100644 index d03ad13ad4..0000000000 --- a/packages/react-table/src/aaa.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { Table, Button } from '../../uiw'; - -const columns = [ - { - // title: '姓名', - width: 90008, - ellipsis: true, - // title: ({ key }) => { - // return ( - // 字段: {key} - // ) - // }, - key: 'name', - }, - { - title: '年龄', - style: { color: 'red' }, - width: 100, - key: 'age', - }, -]; -const dataSource = [ - { - name: '邓紫棋', - age: '12', - info: '又名G.E.M.,原名邓诗颖,1991年8月16日生于中国上海,中国香港创作型女歌手。', - edit: '', - }, - { name: '李易峰', age: '32', info: '1987年5月4日出生于四川成都,中国内地男演员、流行乐歌手、影视制片人', edit: '' }, -]; -const Demo = () => ( -
- } - /> - -); From 2bb39f933a20f67782e78e9320236662cbd6037f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Mon, 21 Mar 2022 19:51:01 +0800 Subject: [PATCH 04/19] =?UTF-8?q?feat(Table):=20Table=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=9B=BA=E5=AE=9A=E5=88=97=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/README.md | 82 ++++++++++++++++++++--- packages/react-table/src/TableTr.tsx | 26 +++++-- packages/react-table/src/ThComponent.tsx | 45 +++++++++++++ packages/react-table/src/Thead.tsx | 44 +++++++----- packages/react-table/src/index.tsx | 49 +++++++++++++- packages/react-table/src/style/index.less | 52 +++++++++++++- packages/react-table/src/util.ts | 13 +++- 7 files changed, 273 insertions(+), 38 deletions(-) create mode 100644 packages/react-table/src/ThComponent.tsx diff --git a/packages/react-table/README.md b/packages/react-table/README.md index d9c45704d7..fa8a7d876a 100644 --- a/packages/react-table/README.md +++ b/packages/react-table/README.md @@ -873,6 +873,64 @@ const Demo = () => ( ReactDOM.render(, _mount_); ``` +### 固定列 + +通过使用 fixed 使其列固定 +> ⚠️ 注意: 若并没有 scroll 滚动条,fixed 属性并不会有直观的效果 + + + +```jsx +import ReactDOM from 'react-dom'; +import { Table, Button } from 'uiw'; + +const columns = [ + { + title: '姓名', + ellipsis: true, + // fixed: true, + width: 50, + key: 'name', + }, { + // fixed: true, + title: '年龄', + width: 50, + style: { color: 'red' }, + key: 'age', + }, { + title: '地址', + width: 50, + key: 'info', + }, { + title: '操作', + key: 'edit', + width: 98, + fixed: 'right', + render: (text, key, rowData, rowNumber, columnNumber) => ( +
+ + +
+ ), + }, +]; +const dataSource = [ + { name: '邓紫棋', age: '12', info: '又名G.E.M.,原名邓诗颖,1991年8月16日生于中国上海,中国香港创作型女歌手。', edit: '' }, + { name: '李易峰', age: '32', info: '1987年5月4日出生于四川成都,中国内地男演员、流行乐歌手、影视制片人', edit: '' }, + { name: '范冰冰', age: '23', info: '1981年9月16日出生于山东青岛,中国影视女演员、制片人、流行乐女歌手', edit: '' }, + { name: '杨幂', age: '34', info: '1986年9月12日出生于北京市,中国内地影视女演员、流行乐歌手、影视制片人。', edit: '' }, + { name: 'Angelababy', age: '54', info: '1989年2月28日出生于上海市,华语影视女演员、时尚模特。', edit: '' }, + { name: '唐嫣', age: '12', info: '1983年12月6日出生于上海市,毕业于中央戏剧学院表演系本科班', edit: '' }, + { name: '吴亦凡', age: '4', info: '1990年11月06日出生于广东省广州市,华语影视男演员、流行乐歌手。', edit: '' }, +]; +const Demo = () => ( +
+
+ +); +ReactDOM.render(, _mount_); +``` + ## Props ### Table @@ -881,14 +939,16 @@ ReactDOM.render(, _mount_); |--------- |-------- |--------- |-------- | | columns | 表格列的配置描述,可以内嵌 `children`,以渲染分组表头。| ColumnProps[] | `[]` | | data | 数据数组。| Array[] | `[]` | -| title | 表格标题 | ~~Function(text, key, rowData, rowNumber, columnNumber)~~ /
Function(data: IColumns, rowNum: number, colNum: number)`@3.0.0+` /
String / ReactNode | - | +| title | 表格标题 | ~~Function(text, key, rowData, rowNumber, columnNumber)~~ /
Function(data: IColumns, rowNum: Number, colNum: Number)`@3.0.0+` /
String / ReactNode | - | | footer | 表格尾部 | String/ReactNode | - | | bordered | 是否展示外边框和列边框 | Boolean | - | | empty | 无数据状态 | ReactNode | - | -| onCellHead | 表头单元格点击回调 | ~~`Function(text, key, rowData, rowNumber, columnNumber)`~~ /
Function(data: IColumns, colNum: number, rowNum: number, evn: React.MouseEvent) `@3.0.0+` | - | -| onCell | 单元格点击回调 | ~~`Function(text, key, rowData, rowNumber, columnNumber)`~~ /
Function(data: IColumns, options:{ colNum: number, rowNum: number, keyName: string }, evn: React.MouseEvent) `@3.1.0+` | - | +| onCellHead | 表头单元格点击回调 | ~~`Function(text, key, rowData, rowNumber, columnNumber)`~~ /
Function(data: IColumns, colNum: Number, rowNum: Number, evn: React.MouseEvent) `@3.0.0+` | - | +| onCell | 单元格点击回调 | ~~`Function(text, key, rowData, rowNumber, columnNumber)`~~ /
Function(data: IColumns, options:{ colNum: Number, rowNum: Number, keyName: String }, evn: React.MouseEvent) `@3.1.0+` | - | | expandable | 可展开配置 | ExpandableType | - | -| rowKey | 表格行 key 的取值 | string | - | +| rowKey | 表格行 key 的取值 | String | - | +| scroll | 表格是否可滚动,也可以指定滚动区域的宽、高 | { x?: React.CSSProperties['width'], y?: React.CSSProperties['height'] } | - | + ### ColumnProps @@ -902,9 +962,9 @@ ReactDOM.render(, _mount_); | colSpan | 合并表头行。| Number | - | | ellipsis | 超过宽度将自动省略。`v4.8.7+`| Boolean | `false` | | render | 生成复杂数据的渲染函数,参数分别为当前行的值,当前值的 `key`,行索引数据,当前行号,当前列号。| `Function(text, key, rowData, rowNumber, columnNumber)` | - | -| align | 设置列的对齐方式 | "left"|"center"|"right" | - | -| className | 列样式类名 | string | - | -| scroll | 表格是否可滚动,也可以指定滚动区域的宽、高 | { x?: React.CSSProperties['width'], y?: React.CSSProperties['height'] } | - | +| align | 设置列的对齐方式 | "left"\|"center"\|"right" | - | +| className | 列样式类名 | String | - | +| fixed | 把选择框列固定 | Boolean \|"left"\|"right" | - | ### expandable @@ -914,11 +974,11 @@ ReactDOM.render(, _mount_); |--------- |-------- |--------- |-------- | | expandedRowRender | 自定义展开行| (record, index, expanded) => React.ReactNode | - | | expandIcon | 自定义图标 | (expanded, record, index) => React.ReactNode; | - | -| rowExpandable | 是否允许展开| (record)=>boolean | - | -| defaultExpandAllRows | 初始时,是否展开所有行| boolean | false | +| rowExpandable | 是否允许展开| (record)=>Boolean | - | +| defaultExpandAllRows | 初始时,是否展开所有行| Boolean | false | | defaultExpandedRowKeys | 初始时,默认展开的行 rowKey数组 | Array | - | | expandedRowKeys | 控制展开的行 rowKey数组 | Array | - | | onExpandedRowsChange | 展开的行变化触发 | (expandedRows)=>void | - | | onExpand | 点击展开图标触发 | (expanded,record,index)=>void | - | -| indentSize | 控制树形结构每一层的缩进宽度 | number | 16 | -| childrenColumnName | 指定树形结构的列名 | string | children | +| indentSize | 控制树形结构每一层的缩进宽度 | Number | 16 | +| childrenColumnName | 指定树形结构的列名 | String | children | diff --git a/packages/react-table/src/TableTr.tsx b/packages/react-table/src/TableTr.tsx index 884f3ec0a2..ce05e5c540 100644 --- a/packages/react-table/src/TableTr.tsx +++ b/packages/react-table/src/TableTr.tsx @@ -1,8 +1,9 @@ import React, { useMemo, useState, useEffect } from 'react'; import Icon from '@uiw/react-icon'; -import { TableProps } from './'; +import { LocationWidth, TableProps } from './'; import './style/index.less'; import { noop } from '@uiw/utils'; +import { locationFixed } from './util'; interface TableTrProps { rowKey?: keyof T; @@ -18,6 +19,7 @@ interface TableTrProps { // 层级 hierarchy: number; childrenColumnName: string; + locationWidth: { [key: number]: LocationWidth }; } export default function TableTr(props: TableTrProps) { @@ -33,6 +35,7 @@ export default function TableTr(props: TableTr hierarchy, indentSize, childrenColumnName, + locationWidth, } = props; const [isOpacity, setIsOpacity] = useState(false); const [expandIndex, setExpandIndex] = useState>([]); @@ -88,9 +91,6 @@ export default function TableTr(props: TableTr } } } - if (ellipsis && ellipsis[keyName.key!]) { - objs.className = `${prefixCls}-ellipsis`; - } const isHasChildren = Array.isArray(trData[childrenColumnName]); if (colNum === 0 && (isOpacity || hierarchy || isHasChildren)) { objs.children = ( @@ -101,13 +101,25 @@ export default function TableTr(props: TableTr ); } + if (keyName.fixed) { + if (keyName.fixed === 'right') { + objs.className = `${objs.className} ${prefixCls}-fixed-right`; + } else { + objs.className = `${objs.className} ${prefixCls}-fixed-true`; + } + } return (
+ ); + } +} diff --git a/packages/react-table/src/Thead.tsx b/packages/react-table/src/Thead.tsx index 7af3e644da..5cffc332c0 100644 --- a/packages/react-table/src/Thead.tsx +++ b/packages/react-table/src/Thead.tsx @@ -1,19 +1,30 @@ import React from 'react'; import { IProps, noop } from '@uiw/utils'; -import { TableProps, TableColumns } from './'; +import { TableProps, TableColumns, LocationWidth } from './'; import './style/index.less'; +import ThComponentProps from './ThComponent'; export interface TheadProps extends IProps { data?: TableColumns[][]; onCellHead?: TableProps['onCellHead']; align?: TableColumns['align']; className?: TableColumns['className']; + locationWidth?: { [key: number]: LocationWidth }; + updateLocation?: (params: LocationWidth, index: number) => void; } export default function TheadComponent( props: TheadProps & React.HTMLAttributes = {}, ) { - const { prefixCls = 'w-table', className, data = [], onCellHead = noop, ...other } = props; + const { + prefixCls = 'w-table', + className, + data = [], + onCellHead = noop, + locationWidth, + updateLocation, + ...other + } = props; return ( {data && @@ -21,24 +32,27 @@ export default function TheadComponent( data.map((tds?: TableColumns[], rowNum?: number) => ( {(tds || []).map((item, colNum) => { - const { title, key, render, children, ellipsis, ...thProps } = item; - const titleNode: TableColumns['title'] = - typeof title === 'function' ? title(item, colNum, rowNum!) : title; + const { title, key, render, children, ellipsis, fixed = false, ...thProps } = item; + const titleNode: TableColumns['title'] = ( + + {typeof title === 'function' ? title(item, colNum, rowNum!) : title} + + ); if (thProps.colSpan === 0) { return null; } - if (ellipsis) { - thProps.className = `${thProps.className || ''} ${prefixCls}-ellipsis`; - } return ( - + prefixCls={prefixCls} + onCellHead={onCellHead} + rowNum={rowNum!} + titleNode={titleNode} + locationWidth={locationWidth!} + updateLocation={updateLocation!} + /> ); })} diff --git a/packages/react-table/src/index.tsx b/packages/react-table/src/index.tsx index 1beef63205..445e4492ce 100644 --- a/packages/react-table/src/index.tsx +++ b/packages/react-table/src/index.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useState, useEffect } from 'react'; +import React, { useMemo, useState, useEffect, useRef } from 'react'; import { IProps, HTMLDivProps, noop } from '@uiw/utils'; import Icon from '@uiw/react-icon'; import Thead from './Thead'; @@ -42,6 +42,7 @@ export type TableColumns = { style?: React.CSSProperties; align?: 'left' | 'center' | 'right'; className?: string; + fixed?: boolean | 'left' | 'right'; [key: string]: any; }; @@ -69,6 +70,11 @@ export interface TableProps exten scroll?: { x?: React.CSSProperties['width']; y?: React.CSSProperties['height'] }; } +export interface LocationWidth { + left?: number; + right?: number; + width: number; +} export interface ICellOptions { rowNum: number; colNum: number; @@ -93,6 +99,37 @@ export default function Table(props: TablePro ...other } = props; const [expandIndex, setExpandIndex] = useState>([]); + const [locationWidth, setLocationWidth] = useState<{ [key: number]: LocationWidth }>({}); + const finalLocationWidth = useRef<{ [key: number]: LocationWidth }>({}); + const updateLocation = (params: LocationWidth, index: number) => { + finalLocationWidth.current = { + ...finalLocationWidth.current, + [index]: { + ...finalLocationWidth.current[index], + ...params, + }, + }; + if (index === columns.length - 1) { + setLocationWidth(computed()); + } + }; + const computed = () => { + let left = 0, + right = 0; + for (let index = 0; index < columns.length; index++) { + if (finalLocationWidth.current[index]) { + finalLocationWidth.current[index].left = left; + left = finalLocationWidth.current[index].width + left; + } + } + for (let index = columns.length - 1; index > -1; index--) { + if (finalLocationWidth.current[index]) { + finalLocationWidth.current[index].right = right; + right = finalLocationWidth.current[index].width + right; + } + } + return finalLocationWidth.current; + }; useEffect(() => { if (expandable) { if (expandable.defaultExpandAllRows) { @@ -215,11 +252,19 @@ export default function Table(props: TablePro
+ {objs.children} + + } key={colNum} - // style={keyName?.style} - className={`${objs.className || ''} ${prefixCls}-tr-children-${keyName.align || 'left'} ${ - keyName.className || '' + className={`${prefixCls}-tr-children-${keyName.align || 'left'} ${keyName.className || ''} ${ + objs.className || '' }`} onClick={(evn) => onCell(trData, { rowNum, colNum, keyName: keyName.key! }, evn)} /> diff --git a/packages/react-table/src/ThComponent.tsx b/packages/react-table/src/ThComponent.tsx new file mode 100644 index 0000000000..75bcf81a6f --- /dev/null +++ b/packages/react-table/src/ThComponent.tsx @@ -0,0 +1,45 @@ +import React, { Component } from 'react'; +import ReactDOM from 'react-dom'; +import { TableColumns, TableProps, LocationWidth } from './'; +import { locationFixed } from './util'; + +interface ThComponentProps { + colNum: number; + item: TableColumns; + prefixCls: string; + titleNode: JSX.Element; + onCellHead: TableProps['onCellHead']; + rowNum: number; + locationWidth: { [key: number]: LocationWidth }; + updateLocation: (params: LocationWidth, index: number) => void; +} +export default class ThComponent extends Component> { + componentDidMount() { + const rect = ReactDOM.findDOMNode(this); + this.props.updateLocation({ width: (rect as any).getBoundingClientRect().width }, this.props.colNum); + } + + render() { + const { colNum, prefixCls, item, titleNode, onCellHead, rowNum, locationWidth } = this.props; + const { title, key, render, children, ellipsis, fixed = false, ...thProps } = item; + let cls = ''; + if (fixed) { + if (fixed === 'right') { + cls = prefixCls + '-fixed-right'; + } else { + cls = prefixCls + '-fixed-true'; + } + } + return ( + onCellHead?.(item, colNum, rowNum!, evn)} + > + {titleNode} +
onCellHead(item, colNum, rowNum!, evn)} - > - {titleNode} -
{title && } - {columns && columns.length > 0 && } + {columns && columns.length > 0 && ( + + )} {data && data.length > 0 && ( tbody > tr { transition: all 0.3s; + > td { + background-color: #fff; + position: relative; + z-index: 1; + } &:hover, &:hover:nth-child(2n) { - background-color: #efefef; + > td { + background-color: #efefef; + } } &:nth-child(2n) { - background-color: #f9f9f9; + > td { + background-color: #f9f9f9; + } } } > thead { > tr > th { font-weight: normal; padding: 8px; + background-color: #f6f9fb; + position: relative; + z-index: 1; } > tr, tr:nth-child(2n) { @@ -47,6 +59,7 @@ white-space: nowrap; text-overflow: ellipsis; word-break: keep-all; + display: block; } &-tr-children-center { text-align: center; @@ -57,6 +70,41 @@ &-tr-children-right { text-align: right; } + &-fixed-true { + position: sticky !important; + z-index: 2 !important; + // border: 0; 透风 1px + } + &-fixed-right { + position: sticky !important; + z-index: 2 !important; + // border: 0; 透风 1px + } + &-fixed-true::after { + box-shadow: inset 10px 0 8px -8px rgb(0 0 0 / 15%); + position: absolute; + top: 0; + right: 0; + bottom: -1px; + width: 30px; + transform: translateX(100%); + transition: box-shadow 0.3s; + content: ''; + pointer-events: none; + } + &-fixed-right::after { + box-shadow: inset -10px 0 8px -8px rgb(0 0 0 / 15%); + position: absolute; + top: 0; + bottom: -1px; + left: 0; + width: 30px; + transform: translateX(-100%); + transition: box-shadow 0.3s; + content: ''; + pointer-events: none; + border-right: 1px solid #f0f0f0; + } &-bordered { > table { tr > th, diff --git a/packages/react-table/src/util.ts b/packages/react-table/src/util.ts index 68a0c8236f..5f96cf9d80 100644 --- a/packages/react-table/src/util.ts +++ b/packages/react-table/src/util.ts @@ -1,4 +1,5 @@ -import { TableColumns } from './'; +import { TableColumns, LocationWidth } from './'; +import React from 'react'; /** * Get colspan number @@ -127,3 +128,13 @@ export function getAllColumnsKeys(data: TableColumns[], keys: TableColumns } return keys; } + +export function locationFixed( + fixed: boolean | 'left' | 'right', + location: { [key: number]: LocationWidth }, + index: number, +): React.CSSProperties { + if (!fixed) return {}; + if (fixed === 'right') return { right: location[index]?.right }; + return { left: location[index]?.left }; +} From a86201ea64ebfc9fd165b173fe0bc7c57c589337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Mon, 21 Mar 2022 19:54:35 +0800 Subject: [PATCH 05/19] =?UTF-8?q?feat(Table):=20Table=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=9B=BA=E5=AE=9A=E5=88=97=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/src/ThComponent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-table/src/ThComponent.tsx b/packages/react-table/src/ThComponent.tsx index 75bcf81a6f..5711369687 100644 --- a/packages/react-table/src/ThComponent.tsx +++ b/packages/react-table/src/ThComponent.tsx @@ -16,7 +16,7 @@ interface ThComponentProps { export default class ThComponent extends Component> { componentDidMount() { const rect = ReactDOM.findDOMNode(this); - this.props.updateLocation({ width: (rect as any).getBoundingClientRect().width }, this.props.colNum); + this.props.updateLocation({ width: (rect as Element).getBoundingClientRect().width }, this.props.colNum); } render() { From 35816f77babcafb01a3030fff02f49bc90b53aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Mon, 21 Mar 2022 20:43:33 +0800 Subject: [PATCH 06/19] doc(Table): Update README.md --- packages/react-table/README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/react-table/README.md b/packages/react-table/README.md index fa8a7d876a..0fc5d69ad8 100644 --- a/packages/react-table/README.md +++ b/packages/react-table/README.md @@ -954,17 +954,17 @@ ReactDOM.render(, _mount_); 列描述数据对象,是 columns 中的一项, -| 参数 | 说明 | 类型 | 默认值 | -|--------- |-------- |--------- |-------- | -| title | 列头显示文字。| ReactNode | - | -| key | 需要的 key,可以忽略这个属性,如果标题带有 `render` 函数,那么这个 `key` 为必须非常重要。| String | - | -| width | 列宽度。| Number | - | -| colSpan | 合并表头行。| Number | - | -| ellipsis | 超过宽度将自动省略。`v4.8.7+`| Boolean | `false` | -| render | 生成复杂数据的渲染函数,参数分别为当前行的值,当前值的 `key`,行索引数据,当前行号,当前列号。| `Function(text, key, rowData, rowNumber, columnNumber)` | - | -| align | 设置列的对齐方式 | "left"\|"center"\|"right" | - | -| className | 列样式类名 | String | - | -| fixed | 把选择框列固定 | Boolean \|"left"\|"right" | - | +| 参数 | 说明 | 类型 | 默认值 | 版本 | +|--------- |-------- |--------- |-------- |-------- | +| title | 列头显示文字。| ReactNode | - | - | +| key | 需要的 key,可以忽略这个属性,如果标题带有 `render` 函数,那么这个 `key` 为必须非常重要。| String | - | - | +| width | 列宽度。| Number | - | - | +| colSpan | 合并表头行。| Number | - | - | +| ellipsis | 超过宽度将自动省略。`v4.8.7+`| Boolean | `false` | - | +| render | 生成复杂数据的渲染函数,参数分别为当前行的值,当前值的 `key`,行索引数据,当前行号,当前列号。| `Function(text, key, rowData, rowNumber, columnNumber)` | - | - | +| align | 设置列的对齐方式 | "left"\|"center"\|"right" | - | - | +| className | 列样式类名 | String | - | - | +| fixed | 把选择框列固定 | Boolean \|"left"\|"right" | - | 4.15.1 | ### expandable From 68f82624299c27bfa142d9724b50bf5c2281b657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Tue, 22 Mar 2022 16:30:34 +0800 Subject: [PATCH 07/19] =?UTF-8?q?update(Table):=20Table=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=A0=91=E5=BD=A2=E6=95=B0=E6=8D=AE=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E5=92=8C=E5=8F=AF=E5=B1=95=E5=BC=80=E5=90=8C=E6=97=B6=E5=87=BA?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/README.md | 8 +++----- packages/react-table/src/TableTr.tsx | 6 ++++-- packages/react-table/src/index.tsx | 13 ++++++++++++- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/react-table/README.md b/packages/react-table/README.md index 0fc5d69ad8..de95f97d6c 100644 --- a/packages/react-table/README.md +++ b/packages/react-table/README.md @@ -729,9 +729,6 @@ ReactDOM.render(, _mount_); 可以通过设置 indentSize 以控制每一层的缩进宽度 -> ⚠️ 注意: 树形数据展示和`expandable.expandedRowRender`请不要同时出现,后续或将支持 - - ```jsx import ReactDOM from 'react-dom'; @@ -805,7 +802,7 @@ const Demo = () => {
{title}
) @@ -968,7 +965,8 @@ ReactDOM.render(, _mount_); ### expandable -注意 expandedRowKeys 与 onExpandedRowsChange 必须成对出现 +> ⚠️ 注意: expandedRowKeys 与 onExpandedRowsChange 必须同时出现或不出现 + | 参数 | 说明 | 类型 | 默认值 | |--------- |-------- |--------- |-------- | diff --git a/packages/react-table/src/TableTr.tsx b/packages/react-table/src/TableTr.tsx index ce05e5c540..2f1d2d7cff 100644 --- a/packages/react-table/src/TableTr.tsx +++ b/packages/react-table/src/TableTr.tsx @@ -38,9 +38,11 @@ export default function TableTr(props: TableTr locationWidth, } = props; const [isOpacity, setIsOpacity] = useState(false); + const [childrenIndex, setChildrenIndex] = useState(0); const [expandIndex, setExpandIndex] = useState>([]); useEffect(() => { setIsOpacity(!!data?.find((it) => it[childrenColumnName])); + setChildrenIndex(keys?.findIndex((it) => it.key === 'uiw-expanded') === -1 ? 0 : 1); }, [data]); const IconDom = useMemo(() => { @@ -92,7 +94,7 @@ export default function TableTr(props: TableTr } } const isHasChildren = Array.isArray(trData[childrenColumnName]); - if (colNum === 0 && (isOpacity || hierarchy || isHasChildren)) { + if (colNum === childrenIndex && (isOpacity || hierarchy || isHasChildren)) { objs.children = ( <> {IconDom(key, isHasChildren)} @@ -126,10 +128,10 @@ export default function TableTr(props: TableTr ); })} + {isExpandedDom(trData, rowNum)} {expandIndex.includes(key) && ( )} - {isExpandedDom(trData, rowNum)} ); })} diff --git a/packages/react-table/src/index.tsx b/packages/react-table/src/index.tsx index 445e4492ce..1a2fc640bc 100644 --- a/packages/react-table/src/index.tsx +++ b/packages/react-table/src/index.tsx @@ -131,9 +131,20 @@ export default function Table(props: TablePro return finalLocationWidth.current; }; useEffect(() => { + const childKey = expandable?.childrenColumnName || 'children'; + const deep = (params: TableColumns) => { + const arr1: Array = []; + const arr = params.map((it: T, index: number) => { + if (Array.isArray(it[childKey])) { + arr1.push(...deep(it[childKey])); + } + return rowKey ? it[rowKey] : index; + }); + return [...arr1, ...arr]; + }; if (expandable) { if (expandable.defaultExpandAllRows) { - setExpandIndex(data.map((it, index) => (rowKey ? it[rowKey] : index))); + setExpandIndex(deep(data)); return; } if (expandable.defaultExpandedRowKeys) { From fab96bdd49c5cb923ce3bf85a2226113e5c21e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Wed, 23 Mar 2022 15:55:25 +0800 Subject: [PATCH 08/19] =?UTF-8?q?fix(Table):=20=E4=BF=AE=E5=A4=8DTable=20i?= =?UTF-8?q?ndentSize=20=E4=BC=A0=E9=80=920=E5=A4=B1=E6=95=88=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/src/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-table/src/index.tsx b/packages/react-table/src/index.tsx index 1a2fc640bc..d6e1a2e8ac 100644 --- a/packages/react-table/src/index.tsx +++ b/packages/react-table/src/index.tsx @@ -284,7 +284,7 @@ export default function Table(props: TablePro onCell={onCell} hierarchy={0} isExpandedDom={isExpandedDom} - indentSize={expandable?.indentSize || 16} + indentSize={typeof expandable?.indentSize === 'number' ? expandable?.indentSize : 16} childrenColumnName={expandable?.childrenColumnName || 'children'} /> From 5a5bbdd8977d4ee2fc5ac12fce502d00ac3d4e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Fri, 25 Mar 2022 15:31:42 +0800 Subject: [PATCH 09/19] =?UTF-8?q?fix(Table):=20=E4=BF=AE=E5=A4=8D=20table?= =?UTF-8?q?=20fixed=20=E4=B8=8D=E8=83=BD=E5=AF=B9=E8=A1=A8=E5=A4=B4?= =?UTF-8?q?=E5=88=86=E7=BB=84=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/src/TableTr.tsx | 20 ++++++- packages/react-table/src/ThComponent.tsx | 15 +++-- packages/react-table/src/Thead.tsx | 4 +- packages/react-table/src/index.tsx | 73 ++++++++++++++++++------ packages/react-table/src/util.ts | 4 +- 5 files changed, 87 insertions(+), 29 deletions(-) diff --git a/packages/react-table/src/TableTr.tsx b/packages/react-table/src/TableTr.tsx index 2f1d2d7cff..fcfceb5515 100644 --- a/packages/react-table/src/TableTr.tsx +++ b/packages/react-table/src/TableTr.tsx @@ -1,12 +1,13 @@ import React, { useMemo, useState, useEffect } from 'react'; import Icon from '@uiw/react-icon'; -import { LocationWidth, TableProps } from './'; +import { LocationWidth, TableColumns, TableProps } from './'; import './style/index.less'; import { noop } from '@uiw/utils'; import { locationFixed } from './util'; interface TableTrProps { rowKey?: keyof T; + header: TableColumns[][]; data: T[]; keys: TableProps['columns']; render: { [key: string]: any }; @@ -19,7 +20,7 @@ interface TableTrProps { // 层级 hierarchy: number; childrenColumnName: string; - locationWidth: { [key: number]: LocationWidth }; + locationWidth: { [key: string]: LocationWidth }; } export default function TableTr(props: TableTrProps) { @@ -36,6 +37,7 @@ export default function TableTr(props: TableTr indentSize, childrenColumnName, locationWidth, + header, } = props; const [isOpacity, setIsOpacity] = useState(false); const [childrenIndex, setChildrenIndex] = useState(0); @@ -65,6 +67,14 @@ export default function TableTr(props: TableTr ); }; }, [expandIndex]); + const getIndex = (key: string) => { + let j = 0; + const i = header.findIndex((it) => { + j = it.findIndex((item) => item.key === key); + return j > -1; + }); + return `${i}${j}`; + }; if (!Array.isArray(data) || !data.length) { return null; } @@ -113,7 +123,11 @@ export default function TableTr(props: TableTr return (
{objs.children} diff --git a/packages/react-table/src/ThComponent.tsx b/packages/react-table/src/ThComponent.tsx index 5711369687..83d7c2667c 100644 --- a/packages/react-table/src/ThComponent.tsx +++ b/packages/react-table/src/ThComponent.tsx @@ -10,13 +10,18 @@ interface ThComponentProps { titleNode: JSX.Element; onCellHead: TableProps['onCellHead']; rowNum: number; - locationWidth: { [key: number]: LocationWidth }; - updateLocation: (params: LocationWidth, index: number) => void; + locationWidth: { [key: string]: LocationWidth }; + updateLocation: (params: LocationWidth, index: string, key: string, colSpan?: number) => void; } export default class ThComponent extends Component> { componentDidMount() { - const rect = ReactDOM.findDOMNode(this); - this.props.updateLocation({ width: (rect as Element).getBoundingClientRect().width }, this.props.colNum); + const rect = ReactDOM.findDOMNode(this) as Element; + this.props.updateLocation( + { width: rect.getBoundingClientRect().width }, + `${this.props.rowNum}${this.props.colNum}`, + this.props.item.key!, + this.props.item.colSpan, + ); } render() { @@ -34,7 +39,7 @@ export default class ThComponent extends Component> { onCellHead?.(item, colNum, rowNum!, evn)} > diff --git a/packages/react-table/src/Thead.tsx b/packages/react-table/src/Thead.tsx index 5cffc332c0..d4c600e4cd 100644 --- a/packages/react-table/src/Thead.tsx +++ b/packages/react-table/src/Thead.tsx @@ -9,8 +9,8 @@ export interface TheadProps extends IPr onCellHead?: TableProps['onCellHead']; align?: TableColumns['align']; className?: TableColumns['className']; - locationWidth?: { [key: number]: LocationWidth }; - updateLocation?: (params: LocationWidth, index: number) => void; + locationWidth?: { [key: string]: LocationWidth }; + updateLocation?: (params: LocationWidth, index: string, key: string, colSpan?: number) => void; } export default function TheadComponent( diff --git a/packages/react-table/src/index.tsx b/packages/react-table/src/index.tsx index d6e1a2e8ac..81023bc333 100644 --- a/packages/react-table/src/index.tsx +++ b/packages/react-table/src/index.tsx @@ -74,12 +74,15 @@ export interface LocationWidth { left?: number; right?: number; width: number; + key?: string; + colSpan?: number; } export interface ICellOptions { rowNum: number; colNum: number; keyName: string; } + export default function Table(props: TableProps = {}) { const { prefixCls = 'w-table', @@ -99,35 +102,70 @@ export default function Table(props: TablePro ...other } = props; const [expandIndex, setExpandIndex] = useState>([]); - const [locationWidth, setLocationWidth] = useState<{ [key: number]: LocationWidth }>({}); - const finalLocationWidth = useRef<{ [key: number]: LocationWidth }>({}); - const updateLocation = (params: LocationWidth, index: number) => { + const [locationWidth, setLocationWidth] = useState<{ [key: string]: LocationWidth }>({}); + const finalLocationWidth = useRef<{ [key: string]: LocationWidth }>({}); + const updateLocation = (params: LocationWidth, index: string, key: string, colSpan: number = 0) => { finalLocationWidth.current = { ...finalLocationWidth.current, [index]: { ...finalLocationWidth.current[index], ...params, + key: key, + colSpan, }, }; - if (index === columns.length - 1) { + if (index === `${header.length - 1}${header[header.length - 1].length - 1}`) { setLocationWidth(computed()); } }; - const computed = () => { - let left = 0, - right = 0; - for (let index = 0; index < columns.length; index++) { - if (finalLocationWidth.current[index]) { - finalLocationWidth.current[index].left = left; - left = finalLocationWidth.current[index].width + left; + const deepClumnsLocation = ( + params: Array | number>, + fistIndex: number, + leftOrRight: 'left' | 'right', + isReverse: boolean, + ) => { + let initialValue = 0, + lastIndex = isReverse ? 0 : params.length - 1, + deepParams: Array | number> = []; + params.forEach(() => { + let abs = Math.abs(lastIndex); + const i = `${fistIndex}${abs}`; + if (isReverse) { + lastIndex += 1; + } else { + lastIndex -= 1; } - } - for (let index = columns.length - 1; index > -1; index--) { - if (finalLocationWidth.current[index]) { - finalLocationWidth.current[index].right = right; - right = finalLocationWidth.current[index].width + right; + if (typeof params[abs] === 'number') { + initialValue = (params[abs] as number) + initialValue; + deepParams.push(params[abs]); + return; } - } + if (finalLocationWidth.current[i]) { + finalLocationWidth.current[i][leftOrRight] = initialValue; + initialValue = finalLocationWidth.current[i].width + initialValue; + } + if (Array.isArray((params[abs] as TableColumns).children)) { + deepParams.push(...(params[abs] as TableColumns).children!); + return; + } + if (finalLocationWidth.current[i]) { + deepParams.push(finalLocationWidth.current[i].width); + } else { + const parent = header.find((it) => it.find((it) => it.key === (params[abs] as TableColumns).key)) || []; + const sub = parent.findIndex((it) => it.key === (params[abs] as TableColumns).key); + if (finalLocationWidth.current[`${i[0]}${sub}`]) { + // 合并单元格 + deepParams.push(finalLocationWidth.current[`${i[0]}${sub}`].width); + } + } + }); + if (deepParams.filter((it) => typeof it !== 'number').length) + deepClumnsLocation(deepParams, fistIndex + 1, leftOrRight, isReverse); + }; + + const computed = () => { + deepClumnsLocation(columns, 0, 'left', true); + deepClumnsLocation(columns, 0, 'right', false); return finalLocationWidth.current; }; useEffect(() => { @@ -277,6 +315,7 @@ export default function Table(props: TablePro rowKey={rowKey} locationWidth={locationWidth} data={data} + header={header} keys={self.keys} render={render} ellipsis={ellipsis} diff --git a/packages/react-table/src/util.ts b/packages/react-table/src/util.ts index 5f96cf9d80..c66f8f015e 100644 --- a/packages/react-table/src/util.ts +++ b/packages/react-table/src/util.ts @@ -131,8 +131,8 @@ export function getAllColumnsKeys(data: TableColumns[], keys: TableColumns export function locationFixed( fixed: boolean | 'left' | 'right', - location: { [key: number]: LocationWidth }, - index: number, + location: { [key: string]: LocationWidth }, + index: string, ): React.CSSProperties { if (!fixed) return {}; if (fixed === 'right') return { right: location[index]?.right }; From 2c9f85f4c7607f92f7892bfb0538c373f3742319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Wed, 30 Mar 2022 16:19:22 +0800 Subject: [PATCH 10/19] =?UTF-8?q?fix(Table):=20=E4=BF=AE=E5=A4=8Dtable=20f?= =?UTF-8?q?ix=20=E5=9C=A8=E8=A1=A8=E5=A4=B4=E5=88=86=E7=BB=84=E4=B8=ADfixe?= =?UTF-8?q?d=E5=9B=BA=E5=AE=9A=E4=BD=8D=E7=BD=AE=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/README.md | 14 +++--- packages/react-table/src/TableTr.tsx | 15 ++++--- packages/react-table/src/index.tsx | 65 +++++++++++++--------------- 3 files changed, 48 insertions(+), 46 deletions(-) diff --git a/packages/react-table/README.md b/packages/react-table/README.md index de95f97d6c..d60b6be4d7 100644 --- a/packages/react-table/README.md +++ b/packages/react-table/README.md @@ -80,6 +80,11 @@ const columns = [ style: { color: 'red' }, key: 'name', children: [ + { + title: '英文名字', + width: 100, + key: 'name_en', + }, { title: '中文名字', key: 'cnname', @@ -90,7 +95,7 @@ const columns = [ key: 'firstname', children:[ { title: '姓', key: 'name1', width: 80 }, - { title: '名', key: 'name2', width: 80 }, + { title: '名', key: 'name2', width: 80 }, ] }, { title: '拼音', @@ -101,14 +106,11 @@ const columns = [ ], }, ], - }, { - title: '英文名字', - width: 100, - key: 'name_en', - }, + }, ] }, { title: '其它', + key: 'other', children:[ { title: '生日', key: 'birthday', width: 150 }, { title: '职业', key: 'job', width: 150 }, diff --git a/packages/react-table/src/TableTr.tsx b/packages/react-table/src/TableTr.tsx index fcfceb5515..e9da4362d4 100644 --- a/packages/react-table/src/TableTr.tsx +++ b/packages/react-table/src/TableTr.tsx @@ -115,9 +115,9 @@ export default function TableTr(props: TableTr } if (keyName.fixed) { if (keyName.fixed === 'right') { - objs.className = `${objs.className} ${prefixCls}-fixed-right`; + objs.className = `${prefixCls}-fixed-right`; } else { - objs.className = `${objs.className} ${prefixCls}-fixed-true`; + objs.className = `${prefixCls}-fixed-true`; } } return ( @@ -134,9 +134,14 @@ export default function TableTr(props: TableTr } key={colNum} - className={`${prefixCls}-tr-children-${keyName.align || 'left'} ${keyName.className || ''} ${ - objs.className || '' - }`} + className={[ + prefixCls + '-tr-children-' + (keyName.align || 'left'), + keyName.className, + objs.className, + ] + .filter((it) => it) + .join(' ') + .trim()} onClick={(evn) => onCell(trData, { rowNum, colNum, keyName: keyName.key! }, evn)} /> ); diff --git a/packages/react-table/src/index.tsx b/packages/react-table/src/index.tsx index 81023bc333..dadee6fe4f 100644 --- a/packages/react-table/src/index.tsx +++ b/packages/react-table/src/index.tsx @@ -118,54 +118,47 @@ export default function Table(props: TablePro setLocationWidth(computed()); } }; - const deepClumnsLocation = ( - params: Array | number>, - fistIndex: number, - leftOrRight: 'left' | 'right', - isReverse: boolean, - ) => { + const deepClumnsLocation = (params: Array | number>, fistIndex: number) => { let initialValue = 0, - lastIndex = isReverse ? 0 : params.length - 1, + headerIndex = 0, deepParams: Array | number> = []; - params.forEach(() => { - let abs = Math.abs(lastIndex); - const i = `${fistIndex}${abs}`; - if (isReverse) { - lastIndex += 1; - } else { - lastIndex -= 1; - } - if (typeof params[abs] === 'number') { - initialValue = (params[abs] as number) + initialValue; - deepParams.push(params[abs]); + params.forEach((_, index) => { + const i = `${fistIndex}${headerIndex}`; + if (typeof params[index] === 'number') { + initialValue = (params[index] as number) + initialValue; + deepParams.push(params[index]); return; } if (finalLocationWidth.current[i]) { - finalLocationWidth.current[i][leftOrRight] = initialValue; + finalLocationWidth.current[i].left = initialValue; initialValue = finalLocationWidth.current[i].width + initialValue; + if (Array.isArray((params[index] as TableColumns).children)) { + deepParams.push(...(params[index] as TableColumns).children!); + } else { + deepParams.push(finalLocationWidth.current[i].width); + } } - if (Array.isArray((params[abs] as TableColumns).children)) { - deepParams.push(...(params[abs] as TableColumns).children!); - return; + headerIndex += 1; + }); + (initialValue = 0), (headerIndex = header[fistIndex].length - 1); + for (let index = params.length - 1; index >= 0; index--) { + const i = `${fistIndex}${headerIndex}`; + if (typeof params[index] === 'number') { + initialValue = (params[index] as number) + initialValue; + continue; } if (finalLocationWidth.current[i]) { - deepParams.push(finalLocationWidth.current[i].width); - } else { - const parent = header.find((it) => it.find((it) => it.key === (params[abs] as TableColumns).key)) || []; - const sub = parent.findIndex((it) => it.key === (params[abs] as TableColumns).key); - if (finalLocationWidth.current[`${i[0]}${sub}`]) { - // 合并单元格 - deepParams.push(finalLocationWidth.current[`${i[0]}${sub}`].width); - } + finalLocationWidth.current[i].right = initialValue; + initialValue = finalLocationWidth.current[i].width + initialValue; } - }); - if (deepParams.filter((it) => typeof it !== 'number').length) - deepClumnsLocation(deepParams, fistIndex + 1, leftOrRight, isReverse); + headerIndex -= 1; + } + if (deepParams.filter((it) => typeof it !== 'number').length) deepClumnsLocation(deepParams, fistIndex + 1); }; const computed = () => { - deepClumnsLocation(columns, 0, 'left', true); - deepClumnsLocation(columns, 0, 'right', false); + deepClumnsLocation(columns, 0); + // deepClumnsLocation(columns, 0, 'right', false); return finalLocationWidth.current; }; useEffect(() => { @@ -296,6 +289,8 @@ export default function Table(props: TablePro }, [scroll]); const cls = [prefixCls, className, bordered ? `${prefixCls}-bordered` : null].filter(Boolean).join(' ').trim(); const { header, render, ellipsis } = getLevelItems(self.selfColumns); + console.log('header: ', header); + return (
From f7d88312b0a48e7be0b6c1e5daf1c25e812af199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Wed, 30 Mar 2022 16:22:33 +0800 Subject: [PATCH 11/19] =?UTF-8?q?fix(Table):=20=E4=BF=AE=E5=A4=8Dtable=20f?= =?UTF-8?q?ix=20=E5=9C=A8=E8=A1=A8=E5=A4=B4=E5=88=86=E7=BB=84=E4=B8=ADfixe?= =?UTF-8?q?d=E5=9B=BA=E5=AE=9A=E4=BD=8D=E7=BD=AE=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/src/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react-table/src/index.tsx b/packages/react-table/src/index.tsx index dadee6fe4f..5cf848c83d 100644 --- a/packages/react-table/src/index.tsx +++ b/packages/react-table/src/index.tsx @@ -158,7 +158,6 @@ export default function Table(props: TablePro const computed = () => { deepClumnsLocation(columns, 0); - // deepClumnsLocation(columns, 0, 'right', false); return finalLocationWidth.current; }; useEffect(() => { From 64da40dbb774952d9a3b108e27f24f70fbc8e764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Wed, 30 Mar 2022 16:24:02 +0800 Subject: [PATCH 12/19] =?UTF-8?q?fix(Table):=20=E4=BF=AE=E5=A4=8Dtable=20f?= =?UTF-8?q?ix=20=E5=9C=A8=E8=A1=A8=E5=A4=B4=E5=88=86=E7=BB=84=E4=B8=ADfixe?= =?UTF-8?q?d=E5=9B=BA=E5=AE=9A=E4=BD=8D=E7=BD=AE=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/src/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react-table/src/index.tsx b/packages/react-table/src/index.tsx index 5cf848c83d..51ccb40cce 100644 --- a/packages/react-table/src/index.tsx +++ b/packages/react-table/src/index.tsx @@ -288,7 +288,6 @@ export default function Table(props: TablePro }, [scroll]); const cls = [prefixCls, className, bordered ? `${prefixCls}-bordered` : null].filter(Boolean).join(' ').trim(); const { header, render, ellipsis } = getLevelItems(self.selfColumns); - console.log('header: ', header); return ( From c6dd9b2f8c562a8ba742e78b0816fa206da76bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Fri, 1 Apr 2022 18:18:51 +0800 Subject: [PATCH 13/19] =?UTF-8?q?doc(Table):=20=E5=A2=9E=E5=8A=A0Table?= =?UTF-8?q?=E5=8F=AF=E7=BC=96=E8=BE=91=EF=BC=8C=E5=8F=AF=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E8=A1=8C=E4=BE=8B=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/README.md | 234 ++++++++++++++++++ website/src/routes/components/table/index.tsx | 5 +- 2 files changed, 238 insertions(+), 1 deletion(-) diff --git a/packages/react-table/README.md b/packages/react-table/README.md index d60b6be4d7..c731ffdfed 100644 --- a/packages/react-table/README.md +++ b/packages/react-table/README.md @@ -930,6 +930,240 @@ const Demo = () => ( ReactDOM.render(, _mount_); ``` +### 可编辑 + +利用 render 属性, 传递自定义组件实现 + + +```jsx +import ReactDOM from 'react-dom'; +import { Table, Button, Input, Select } from 'uiw'; + +const columns = (onChange) => [ + { + title: '姓名', + ellipsis: true, + key: 'name', + render: (text,key, rowData) => { + return { + onChange({...rowData, name: value}, rowData.id) + }} + /> + } + }, + { + title: '性别', + key: 'gender', + render: (text,key, rowData) => { + return { + onChange({...rowData, gender: value}, rowData.id) + }} + /> + } + }, + { + title: '年龄', + key: 'age', + render: (text,key, rowData) => { + return { + onChange({...rowData, age: value}, rowData.id) + }} + /> + } + }, + { + title: '地址', + key: 'info', + render: (text,key, rowData) => { + return { + onChange({...rowData, info: value}, rowData.id) + }} + /> + } + }, +]; +const dataSource = [ + { id: 1, gender: "男", name: '邓紫棋', age: '12', info: '又名G.E.M.,原名邓诗颖,1991年8月16日生于中国上海,中国香港创作型女'}, + { id: 2, gender: "男", name: '李易峰', age: '32', info: '1987年5月4日出生于四川成都,中国内地男演员、流行乐歌手、影视制片人', }, + { id: 3, gender: "男", name: '范冰冰', age: '23', info: '1981年9月16日出生于山东青岛,中国影视女演员、制片人、流行乐女歌手', }, + { id: 4, gender: "男", name: '杨幂', age: '34', info: '1986年9月12日出生于北京市,中国内地影视女演员、流行乐歌手、影视制片人。'}, + { id: 5, gender: "男", name: 'Angelababy', age: '54', info: '1989年2月28日出生于上海市,华语影视女演员、时尚模特。', }, + { id: 6, gender: "男", name: '唐嫣', age: '12', info: '1983年12月6日出生于上海市,毕业于中央戏剧学院表演系本科班', }, + { id: 7, gender: "男", name: '吴亦凡', age: '4', info: '1990年11月06日出生于广东省广州市,华语影视男演员、流行乐歌手。', }, +]; +const EditInput = ({edit, value, type, onChange, component, ...other}) => { + const [isEdit, setIsEdit] = React.useState(edit); + const inputRef = React.useRef(); + React.useEffect(()=>{ + isEdit && inputRef.current.focus() + }, [isEdit]) + if(isEdit) { + if(component === "Select") { + return + } + return { + onChange(e.target.value) + setIsEdit(false) + }} + /> + } + return
{ + setIsEdit(true) + }}>{value}
+} +const Demo = () => { + const [data, setData] = React.useState(dataSource) + const onChange = (value, id) => { + setData(data.map(it=>it.id === id ? value : it)) + } + return
+ + +}; +ReactDOM.render(, _mount_); +``` + +### 可编辑行 + +利用 Form 组件和 render 属性, 实现编辑行效果 + + +```jsx +import ReactDOM from 'react-dom'; +import { Table, Button, Input, Select, Form, Notify } from 'uiw'; + +const columns = (actived, setChange, fields) => { + return [ + { + title: '姓名', + ellipsis: true, + key: 'name', + render: (text,key, rowData) => { + if(rowData.id === actived) return fields.name + return text + } + }, + { + title: '性别', + key: 'gender', + render: (text,key, rowData) => { + if(rowData.id === actived) return fields.gender + return text + } + }, + { + title: '年龄', + key: 'age', + render: (text,key, rowData) => { + if(rowData.id === actived) return fields.age + return text + } + }, + { + key: 'id', + render: (id, key, rowData)=>{ + const flag = id === actived + if(flag){ + return <> + + + + } + return + } + } + ] +}; +const dataSource = [ + { id: 1, gender: "男", name: '邓紫棋', age: '12', }, + { id: 2, gender: "男", name: '李易峰', age: '32', }, + { id: 3, gender: "男", name: '范冰冰', age: '23', }, + { id: 4, gender: "男", name: '杨幂', age: '34',}, + { id: 5, gender: "男", name: 'Angelababy', age: '54', }, + { id: 6, gender: "男", name: '唐嫣', age: '12', }, + { id: 7, gender: "男", name: '吴亦凡', age: '4', }, +]; +const Demo = () => { + const [data, setData] = React.useState(dataSource) + const [itemRowData, setItemRowData] = React.useState({}) + const [id, setId] = React.useState() + + const form = React.useRef() + const setChange = (rowData) => { + setId(rowData.id) + setItemRowData(rowData) + form.current.setFields(rowData) + } + + return
{ + if(JSON.stringify(itemRowData) === JSON.stringify(current)) { + Notify.error({ + title: '提交失败!', + description: `表单提交内容并没有修改!`, + }); + return + } + setData(data.map(it=>it.id === current.id ? current : it)) + setId(undefined) + Notify.success({ + title: '提交成功!', + description: '数据已经更新' + }); + }} + fields={{ + name: { + children: + }, + age: { + children: + }, + gender: { + children: + } + }} + > + {({ fields, state, canSubmit }) => { + return ( +
+
+ + ) + }} + +}; +ReactDOM.render(, _mount_); +``` + ## Props ### Table diff --git a/website/src/routes/components/table/index.tsx b/website/src/routes/components/table/index.tsx index ab6b515c44..ab87ae4813 100755 --- a/website/src/routes/components/table/index.tsx +++ b/website/src/routes/components/table/index.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Table, Icon, Empty, Notify, Button, Checkbox, Pagination, Loader, Tooltip } from 'uiw'; +import { Table, Icon, Empty, Notify, Button, Checkbox, Pagination, Loader, Tooltip, Input, Select, Form } from 'uiw'; import Markdown from '../../../components/Markdown'; export default () => ( @@ -15,6 +15,9 @@ export default () => ( Tooltip, Empty, Icon, + Input, + Select, + Form, }} renderPage={async () => { const md = await import('uiw/node_modules/@uiw/react-table/README.md'); From eb632e9d85dd663e0cf23c5b96985531da20489c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Sat, 2 Apr 2022 11:54:22 +0800 Subject: [PATCH 14/19] =?UTF-8?q?doc(Table):=20=E6=9B=B4=E6=96=B0table?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E6=96=87=E6=A1=A3=20=E5=8F=AF=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E8=A1=8C=E4=BE=8B=E5=AD=90=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-table/README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/react-table/README.md b/packages/react-table/README.md index c731ffdfed..bd2970fdab 100644 --- a/packages/react-table/README.md +++ b/packages/react-table/README.md @@ -936,6 +936,7 @@ ReactDOM.render(, _mount_); ```jsx +import React from 'react'; import ReactDOM from 'react-dom'; import { Table, Button, Input, Select } from 'uiw'; @@ -1054,6 +1055,7 @@ ReactDOM.render(, _mount_); ```jsx +import React from 'react'; import ReactDOM from 'react-dom'; import { Table, Button, Input, Select, Form, Notify } from 'uiw'; @@ -1094,7 +1096,14 @@ const columns = (actived, setChange, fields) => { } - return + return } } ] @@ -1148,17 +1157,11 @@ const Demo = () => { children: + } }} > - {({ fields, state, canSubmit }) => { - return ( -
-
- - ) - }} + {({ fields }) =>
} }; ReactDOM.render(, _mount_); From e5dccf7c13aa2610801c1b61adbd62ca3ef3a52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Wed, 6 Apr 2022 16:10:27 +0800 Subject: [PATCH 15/19] =?UTF-8?q?feat(Modal)=20fix(Overlay):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9EModal.show()=E5=BF=AB=E9=80=9F=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=BC=B9=E6=A1=86=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?Overlay=E9=A6=96=E6=AC=A1=E6=89=93=E5=BC=80=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E5=8A=A8=E7=94=BB=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-modal/README.md | 34 +++++++++++++++++++++++++++ packages/react-modal/src/CallShow.tsx | 24 +++++++++++++++++++ packages/react-modal/src/index.tsx | 8 ++++++- packages/react-overlay/src/index.tsx | 4 ++-- 4 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 packages/react-modal/src/CallShow.tsx diff --git a/packages/react-modal/README.md b/packages/react-modal/README.md index 163832f314..22ab69e51b 100644 --- a/packages/react-modal/README.md +++ b/packages/react-modal/README.md @@ -323,6 +323,35 @@ class Demo extends React.Component { ReactDOM.render(, _mount_); ``` +### 快捷弹出 + +使用 show() 可以快捷地弹出确认框。接受的参数与 ModalProps 一样, 只是少了 isOpen 与 onClosed + + +```jsx +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Modal, ButtonGroup, Button } from 'uiw'; + +class Demo extends React.Component { + onClick() { + Modal.show({ + confirmText: "知道了", + children: "快捷提示", + onConfirm: () => console.log('您点击了确定按钮!'), + }) + } + render() { + return ( +
+ +
+ ) + } +} +ReactDOM.render(, _mount_); +``` + ## Props | 参数 | 说明 | 类型 | 默认值 | @@ -345,4 +374,9 @@ ReactDOM.render(, _mount_); | isOpen[``](#/components/overlay) | 对话框是否可见 | Boolean | `false` | | maskClosable[``](#/components/overlay) | 点击遮罩层是否允许关闭 | Boolean | `true` | +## Modal.show() + +继承 ModalProps, 除了 isOpen 与 onClosed + + 更多属性文档请参考 [Overlay](#/components/overlay)。 diff --git a/packages/react-modal/src/CallShow.tsx b/packages/react-modal/src/CallShow.tsx new file mode 100644 index 0000000000..5995fb63ef --- /dev/null +++ b/packages/react-modal/src/CallShow.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import Modal, { ModalProps } from './'; + +export default function CallShow(props: Omit, 'isOpen'> & { children: React.ReactNode }) { + const { title = '提示框', children, ...other } = props; + const dv = document.createElement('div'); + dv.id = 'uiw-modal-call-show-element'; + document.body.appendChild(dv); + ReactDOM.render( + { + document.getElementById('uiw-modal-call-show-element')!.remove(); + }} + > + {' '} + {children} + , + document.getElementById('uiw-modal-call-show-element'), + ); +} diff --git a/packages/react-modal/src/index.tsx b/packages/react-modal/src/index.tsx index 618034454e..1cc3fed08f 100644 --- a/packages/react-modal/src/index.tsx +++ b/packages/react-modal/src/index.tsx @@ -4,6 +4,7 @@ import Button, { ButtonType, ButtonProps } from '@uiw/react-button'; import Icon, { IconProps } from '@uiw/react-icon'; import { IProps, noop } from '@uiw/utils'; import './style/index.less'; +import CallShow from './CallShow'; export interface ModalProps extends IProps, OverlayProps { type?: ButtonType; @@ -27,7 +28,9 @@ export interface ModalProps extends IProps, OverlayProps { onConfirm?: (evn: React.MouseEvent & MouseEvent) => void; } -export default React.forwardRef((props, ref) => { +const Modal: React.ForwardRefExoticComponent & React.RefAttributes> & { + show?: React.ReactNode; +} = React.forwardRef((props, ref) => { const { prefixCls = 'w-modal', className, @@ -129,3 +132,6 @@ export default React.forwardRef((props, ref) => { ); }); + +Modal.show = CallShow; +export default Modal; diff --git a/packages/react-overlay/src/index.tsx b/packages/react-overlay/src/index.tsx index 197b2ca270..3c265bc29d 100644 --- a/packages/react-overlay/src/index.tsx +++ b/packages/react-overlay/src/index.tsx @@ -61,7 +61,8 @@ export default function Overlay(props: OverlayProps) { ...otherProps } = props; - const [isOpen, setIsOpen] = useState(props.isOpen || false); + const [isOpen, setIsOpen] = useState(); + // const [isOpen, setIsOpen] = useState(props.isOpen || false); const [visible, setVisible] = useState(false); const container = useRef(null); const overlay = useRef(null); @@ -127,7 +128,6 @@ export default function Overlay(props: OverlayProps) { // setVisible(false) // } } - const TransitionGroupComp = ( Date: Wed, 6 Apr 2022 16:13:24 +0800 Subject: [PATCH 16/19] =?UTF-8?q?feat(Modal)=20fix(Overlay):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9EModal.show()=E5=BF=AB=E9=80=9F=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=BC=B9=E6=A1=86=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?Overlay=E9=A6=96=E6=AC=A1=E6=89=93=E5=BC=80=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E5=8A=A8=E7=94=BB=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-modal/src/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/react-modal/src/index.tsx b/packages/react-modal/src/index.tsx index 1cc3fed08f..4a1d8c438d 100644 --- a/packages/react-modal/src/index.tsx +++ b/packages/react-modal/src/index.tsx @@ -29,7 +29,11 @@ export interface ModalProps extends IProps, OverlayProps { } const Modal: React.ForwardRefExoticComponent & React.RefAttributes> & { - show?: React.ReactNode; + show?: ( + props: Omit, 'isOpen'> & { + children: React.ReactNode; + }, + ) => void; } = React.forwardRef((props, ref) => { const { prefixCls = 'w-modal', From 365dd473117b43d1a0c44398cd232f0cb07d306a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Wed, 6 Apr 2022 16:19:15 +0800 Subject: [PATCH 17/19] =?UTF-8?q?feat(Modal)=20fix(Overlay):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9EModal.show()=E5=BF=AB=E9=80=9F=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=BC=B9=E6=A1=86=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?Overlay=E9=A6=96=E6=AC=A1=E6=89=93=E5=BC=80=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E5=8A=A8=E7=94=BB=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-modal/src/CallShow.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react-modal/src/CallShow.tsx b/packages/react-modal/src/CallShow.tsx index 5995fb63ef..3788ba3736 100644 --- a/packages/react-modal/src/CallShow.tsx +++ b/packages/react-modal/src/CallShow.tsx @@ -16,7 +16,6 @@ export default function CallShow(props: Omit, 'isOp document.getElementById('uiw-modal-call-show-element')!.remove(); }} > - {' '} {children} , document.getElementById('uiw-modal-call-show-element'), From 175344cae6659fb716733175994ab12639c267c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Wed, 6 Apr 2022 16:39:51 +0800 Subject: [PATCH 18/19] =?UTF-8?q?feat(Modal)=20fix(Overlay):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9EModal.show()=E5=BF=AB=E9=80=9F=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=BC=B9=E6=A1=86=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?Overlay=E9=A6=96=E6=AC=A1=E6=89=93=E5=BC=80=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E5=8A=A8=E7=94=BB=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-modal/README.md | 4 ++-- packages/react-modal/src/CallShow.tsx | 2 +- packages/react-modal/src/index.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-modal/README.md b/packages/react-modal/README.md index 22ab69e51b..9087354f91 100644 --- a/packages/react-modal/README.md +++ b/packages/react-modal/README.md @@ -374,9 +374,9 @@ ReactDOM.render(, _mount_); | isOpen[``](#/components/overlay) | 对话框是否可见 | Boolean | `false` | | maskClosable[``](#/components/overlay) | 点击遮罩层是否允许关闭 | Boolean | `true` | -## Modal.show() +## Modal.show(params) -继承 ModalProps, 除了 isOpen 与 onClosed +params: Omit & { children: React.ReactNode } 更多属性文档请参考 [Overlay](#/components/overlay)。 diff --git a/packages/react-modal/src/CallShow.tsx b/packages/react-modal/src/CallShow.tsx index 3788ba3736..a1c1892db3 100644 --- a/packages/react-modal/src/CallShow.tsx +++ b/packages/react-modal/src/CallShow.tsx @@ -2,7 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import Modal, { ModalProps } from './'; -export default function CallShow(props: Omit, 'isOpen'> & { children: React.ReactNode }) { +export default function CallShow(props: Omit & { children: React.ReactNode }) { const { title = '提示框', children, ...other } = props; const dv = document.createElement('div'); dv.id = 'uiw-modal-call-show-element'; diff --git a/packages/react-modal/src/index.tsx b/packages/react-modal/src/index.tsx index 4a1d8c438d..2a1ea449a8 100644 --- a/packages/react-modal/src/index.tsx +++ b/packages/react-modal/src/index.tsx @@ -30,7 +30,7 @@ export interface ModalProps extends IProps, OverlayProps { const Modal: React.ForwardRefExoticComponent & React.RefAttributes> & { show?: ( - props: Omit, 'isOpen'> & { + props: Omit & { children: React.ReactNode; }, ) => void; From 05a9cd07fb70fb051df38485ae1024dd24ec9509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E9=91=AB?= <1192065030@qq.com> Date: Wed, 6 Apr 2022 16:47:30 +0800 Subject: [PATCH 19/19] =?UTF-8?q?feat(Modal)=20fix(Overlay):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9EModal.show()=E5=BF=AB=E9=80=9F=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=BC=B9=E6=A1=86=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?Overlay=E9=A6=96=E6=AC=A1=E6=89=93=E5=BC=80=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E5=8A=A8=E7=94=BB=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/react-modal/src/index.tsx | 207 ++++++++++++++--------------- 1 file changed, 103 insertions(+), 104 deletions(-) diff --git a/packages/react-modal/src/index.tsx b/packages/react-modal/src/index.tsx index 2a1ea449a8..268c5053ed 100644 --- a/packages/react-modal/src/index.tsx +++ b/packages/react-modal/src/index.tsx @@ -28,114 +28,113 @@ export interface ModalProps extends IProps, OverlayProps { onConfirm?: (evn: React.MouseEvent & MouseEvent) => void; } -const Modal: React.ForwardRefExoticComponent & React.RefAttributes> & { - show?: ( - props: Omit & { - children: React.ReactNode; - }, - ) => void; -} = React.forwardRef((props, ref) => { - const { - prefixCls = 'w-modal', - className, - children, - useButton = true, - usePortal = true, - autoFocus = false, - isOpen: _ = false, - title, - cancelText, - cancelButtonProps, - confirmButtonProps, - content, - confirmText = '确认', - type = 'light', - icon, - maxWidth = 500, - minWidth = 320, - width, - isCloseButtonShown = true, - onCancel = noop, - onConfirm = noop, - bodyStyle, - ...other - } = props; - const [isOpen, setIsOpen] = useState(props.isOpen); - useEffect(() => { - if (props.isOpen !== isOpen) { - setIsOpen(props.isOpen); - } - }, [props.isOpen]); +type ShowModalProps = { + show?: (props: Omit & { children: React.ReactNode }) => void; +}; + +const Modal: React.ForwardRefExoticComponent> & ShowModalProps = + React.forwardRef((props, ref) => { + const { + prefixCls = 'w-modal', + className, + children, + useButton = true, + usePortal = true, + autoFocus = false, + isOpen: _ = false, + title, + cancelText, + cancelButtonProps, + confirmButtonProps, + content, + confirmText = '确认', + type = 'light', + icon, + maxWidth = 500, + minWidth = 320, + width, + isCloseButtonShown = true, + onCancel = noop, + onConfirm = noop, + bodyStyle, + ...other + } = props; + const [isOpen, setIsOpen] = useState(props.isOpen); + useEffect(() => { + if (props.isOpen !== isOpen) { + setIsOpen(props.isOpen); + } + }, [props.isOpen]); - const [loading, setLoading] = useState(false); - const cls = [prefixCls, className, type ? `${type}` : null].filter(Boolean).join(' ').trim(); - function onClose() { - setIsOpen(false); - } - async function handleCancel(e: React.MouseEvent & MouseEvent) { - setLoading(true); - try { - onCancel && (await onCancel(e)); - } catch (e) {} - setIsOpen(false); - setLoading(false); - } - async function handleConfirm(e: React.MouseEvent & MouseEvent) { - setLoading(true); - try { - onConfirm && (await onConfirm(e)); - } catch (e) {} - setIsOpen(false); - setLoading(false); - } - return ( - -
-
- {(title || icon) && ( -
- {icon && } - {title &&

{title}

} - {isCloseButtonShown &&
+ )} +
+ {children || content}
- )} -
- {children || content} -
- {useButton && ( -
- - {cancelText && ( - - )} -
- )} + {cancelText && ( + + )} +
+ )} +
- -
- ); -}); +
+ ); + }); Modal.show = CallShow; export default Modal;