diff --git a/CHANGELOG.md b/CHANGELOG.md
index 054fa8d5c..972d0a19f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,7 +37,6 @@ All notable changes to this project will be documented in this file. See [standa
### Bug Fixes
- fix immediate option in userList ([#378](https://github.com/DTStack/dt-react-component/issues/378)) ([b8992f3](https://github.com/DTStack/dt-react-component/commit/b8992f38f918dde10cb6349e39aca2c524e70853))
- > > > > > > > 272326794683ecd3ed1846ad38fd4258b23dc0f7
## [4.2.0](https://github.com/DTStack/dt-react-component/compare/v4.1.0...v4.2.0) (2023-08-24)
diff --git a/docs/guide/migration-v4.md b/docs/guide/migration-v4.md
index 614e8cc60..7a6962041 100644
--- a/docs/guide/migration-v4.md
+++ b/docs/guide/migration-v4.md
@@ -150,9 +150,10 @@ useCookieListener(
- 新增 `observerEle` 属性,支持自定义监听元素。
-#### SpreadSheet [#325](https://github.com/DTStack/dt-react-component/pull/325)
+#### SpreadSheet [#325](https://github.com/DTStack/dt-react-component/pull/325)、[#545](https://github.com/DTStack/dt-react-component/pull/545)
- 新增 `className` 属性,可自定义外层组件的 class 名。
+- 删除 `showCopyWithHeader` 属性,使用 `copyTypes` 属性代替,值为数组,可传入 'copyData'、'copyHeaders'、'copyHeadersAndData',分别代表的功能为:复制值、复制列名、复制列名和值。
#### KeyEventListener [#326](https://github.com/DTStack/dt-react-component/pull/326)
diff --git a/src/spreadSheet/__tests__/index.test.tsx b/src/spreadSheet/__tests__/index.test.tsx
index 9c147915f..83f304ab9 100644
--- a/src/spreadSheet/__tests__/index.test.tsx
+++ b/src/spreadSheet/__tests__/index.test.tsx
@@ -37,7 +37,7 @@ describe('test spreadSheet ', () => {
const { getByText, unmount } = render();
const cell = getByText('zhangsan');
fireEvent.contextMenu(cell);
- const copyBtn = getByText('复制');
+ const copyBtn = getByText('复制值');
expect(copyBtn).toBeInTheDocument();
fireEvent.click(copyBtn);
unmount();
@@ -45,11 +45,27 @@ describe('test spreadSheet ', () => {
test('copy value with header', () => {
const { getByText, unmount } = render(
-
+
);
const cell = getByText('zhangsan');
fireEvent.contextMenu(cell);
- const copyBtn = getByText('复制值以及列名');
+ const copyBtn = getByText('复制值');
+ expect(copyBtn).toBeInTheDocument();
+ fireEvent.click(copyBtn);
+ unmount();
+ });
+
+ test('copy value with header', () => {
+ const { getByText, unmount } = render(
+
+ );
+ const cell = getByText('zhangsan');
+ fireEvent.contextMenu(cell);
+ const copyBtn = getByText('复制列名和值');
expect(copyBtn).toBeInTheDocument();
fireEvent.click(copyBtn);
unmount();
diff --git a/src/spreadSheet/demos/basic.tsx b/src/spreadSheet/demos/basic.tsx
index 5e308a4a1..e2c984980 100644
--- a/src/spreadSheet/demos/basic.tsx
+++ b/src/spreadSheet/demos/basic.tsx
@@ -3,14 +3,35 @@ import { SpreadSheet } from 'dt-react-component';
export default () => {
return (
-
+ <>
+ 右键菜单:复制值、复制列名
+
+
+
+ 右键菜单:复制值、复制列名、复制列名和值
+
+ >
);
};
diff --git a/src/spreadSheet/demos/changeData.tsx b/src/spreadSheet/demos/changeData.tsx
new file mode 100644
index 000000000..dc27ebc72
--- /dev/null
+++ b/src/spreadSheet/demos/changeData.tsx
@@ -0,0 +1,51 @@
+import React, { useRef, useState } from 'react';
+import { Button } from 'antd';
+import { SpreadSheet } from 'dt-react-component';
+
+export default () => {
+ const _columns = ['name', 'gender', 'age', 'address'];
+ const _data = [
+ ['zhangsan', 'male', '20', 'xihu'],
+ ['lisi', 'male', '18', 'yuhang'],
+ [' 前面有空格', '后面有空格 ', '中间有 空 格', 'yuhang'],
+ ];
+ const [columns, setColumns] = useState(_columns);
+ const [data, setData] = useState(_data);
+ const hotTableInstanceRef = useRef(null);
+
+ const handleData = () => {
+ setData(data?.length === 2 ? _data : _data.slice(0, 2));
+ };
+
+ const handleColumns = () => {
+ setColumns(columns?.length === 3 ? _columns : _columns.slice(0, 3));
+ };
+
+ const handleRef = () => {
+ console.log(hotTableInstanceRef?.current?.hotInstance?.getData());
+ };
+
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+};
diff --git a/src/spreadSheet/index.md b/src/spreadSheet/index.md
index 06aab0348..12c8c2972 100644
--- a/src/spreadSheet/index.md
+++ b/src/spreadSheet/index.md
@@ -3,7 +3,7 @@ title: SpreadSheet 多功能表
group: 组件
toc: content
demo:
- cols: 2
+ cols: 1
---
# SpreadSheet 多功能表
@@ -14,16 +14,17 @@ demo:
## 示例
-基础使用
+
+
## API
### SpreadSheet
-| 参数 | 说明 | 类型 | 默认值 |
-| -------------------------- | -------------------------------------- | ----------------- | ------ |
-| data | 表格数据 | `Array(二维数组)` | - |
-| columns | 列名 | `Array` | - |
-| className | 外层组件的 class 名 | `string` | - |
-| options.showCopyWithHeader | 右键菜单中是否展示“复制值以及列名”按钮 | `boolean` | - |
-| options.trimWhitespace | 是否去除内容里的空格 | `boolean` | true |
+| 参数 | 说明 | 类型 | 默认值 |
+| ---------------------- | ------------------------------------------------------ | ------------------------------------------------------------ | -------------- |
+| data | 表格数据 | `Array(二维数组)` | - |
+| columns | 列名 | `Array` | - |
+| className | 外层组件的 class 名 | `string` | - |
+| options.copyTypes | 右键菜单中展示的选项 复制值/复制列名/复制列名和值 按钮 | `Array<'copyData' \| 'copyHeaders' \| 'copyHeadersAndData'>` | "['copyData']" |
+| options.trimWhitespace | 是否去除内容里的空格 | `boolean` | true |
diff --git a/src/spreadSheet/index.tsx b/src/spreadSheet/index.tsx
index 6086683f9..758935477 100644
--- a/src/spreadSheet/index.tsx
+++ b/src/spreadSheet/index.tsx
@@ -8,9 +8,11 @@ import CopyUtils from '../utils/copy';
import 'handsontable/dist/handsontable.full.css';
import './style.scss';
+type ICopyType = 'copyData' | 'copyHeaders' | 'copyHeadersAndData';
+
type IOptions = HotTableProps & {
- /** 是否展示复制值以及列名 */
- showCopyWithHeader?: boolean;
+ // 右键菜单中展示的选项 复制值/复制列名/复制列名和值 按钮 */
+ copyTypes?: ICopyType[];
};
export interface ISpreadSheetProps {
@@ -33,10 +35,8 @@ const SpreadSheet: React.FC = forwardRef(
const tableRef = useRef(null);
const copyUtils = new CopyUtils();
const _timer = useRef();
- const { showCopyWithHeader, ...restProps } = options || {};
- useImperativeHandle(ref, () => ({
- tableRef,
- }));
+ const { copyTypes = [], ...restProps } = options || {};
+ useImperativeHandle(ref, () => tableRef.current);
useEffect(() => {
if (tableRef.current) {
removeRenderClock();
@@ -53,7 +53,7 @@ const SpreadSheet: React.FC = forwardRef(
clearTimeout(_timer.current);
};
- const getData = () => {
+ const getShowData = () => {
let showData = data;
if (!showData?.length) {
const emptyArr = new Array(columns.length).fill('', 0, columns.length);
@@ -75,56 +75,101 @@ const SpreadSheet: React.FC = forwardRef(
}
};
- const beforeCopy = (arr: any[]) => {
- /**
- * 去除格式化
- */
+ /**
+ * 去除格式化
+ */
+ const beforeCopy = (arr: Array>) => {
const value = arr
.map((row: any[]) => {
return row.join('\t');
})
.join('\n');
+
copyUtils.copy(value);
return false;
};
const getContextMenu = () => {
- const items: Record = {
- copy: {
- name: '复制',
- callback: function (this: any, _key: any) {
- const indexArr = this.getSelected();
- // eslint-disable-next-line prefer-spread
- const copyDataArr = this.getData.apply(this, indexArr[0]);
- beforeCopy(copyDataArr);
- },
- },
+ // 获取值
+ const getCopyData = () => {
+ // 调用的是 handsontable 的方法(在 handsontable.d.ts)
+ const selectedIndexArr = tableRef.current?.hotInstance?.getSelected();
+ let dataArr: Array = [];
+
+ if (Array.isArray(selectedIndexArr)) {
+ selectedIndexArr.forEach((arr, index) => {
+ const [r, c, r2, c2] = arr || [];
+ const colData: [] =
+ tableRef.current?.hotInstance?.getData(r, c, r2, c2) || [];
+ if (index === 0) {
+ dataArr.push(...colData);
+ } else {
+ dataArr = dataArr.map((item: any[], index: number) => {
+ return item.concat(colData[index]);
+ });
+ }
+ });
+ }
+ return dataArr;
};
- if (showCopyWithHeader) {
- const copyWithHeaderItem = {
- name: '复制值以及列名',
- callback: function (this: any, _key: any, selection: any) {
- const indexArr = this.getSelected();
- // eslint-disable-next-line prefer-spread
- let copyDataArr = this.getData.apply(this, indexArr[0]);
- const columnStart = selection?.[0]?.start?.col;
- const columnEnd = selection?.[0]?.end?.col;
- let columnArr;
+ // 获取列名
+ const getCopyHeaders = (selection: Array) => {
+ let headerArr: Array = [];
+ if (Array.isArray(selection)) {
+ selection.forEach((it) => {
+ const columnStart = it.start?.col;
+ const columnEnd = it.end?.col;
if (columnStart !== undefined && columnEnd !== undefined) {
- columnArr = columns.slice(columnStart, columnEnd + 1);
- }
- if (columnArr) {
- copyDataArr = [columnArr, ...copyDataArr];
+ headerArr = headerArr.concat(columns.slice(columnStart, columnEnd + 1));
}
- beforeCopy(copyDataArr);
- },
- };
- // 目前版本不支持 copy_with_column_headers 暂时用 cut 代替,以达到与copy类似的表现
- items['cut'] = copyWithHeaderItem;
+ });
+ }
+ return headerArr;
+ };
+
+ const copyDataItem = {
+ name: '复制值',
+ callback: function (_key: string) {
+ const copyDataArr = getCopyData();
+ beforeCopy(copyDataArr);
+ },
+ };
+ const copyHeadersItem = {
+ name: '复制列名',
+ callback: function (_key: string, selection: Array) {
+ const copyHeaders = getCopyHeaders(selection);
+ beforeCopy([copyHeaders]);
+ },
+ };
+ const copyHeadersAndDataItem = {
+ name: '复制列名和值',
+ callback: function (_key: string, selection: Array) {
+ const copyDataArr = getCopyData();
+ const copyHeaders = getCopyHeaders(selection);
+ beforeCopy([copyHeaders, ...copyDataArr]);
+ },
+ };
+
+ // 目前 items 在 https://github.com/handsontable/handsontable/blob/6.2.2/handsontable.d.ts#L779,自定义方法也可以被执行
+ const items: Partial> = {};
+ if (Array.isArray(copyTypes) && copyTypes?.length) {
+ // 复制值
+ if (copyTypes.includes('copyData')) {
+ items['copyData'] = copyDataItem;
+ }
+ // 复制列名
+ if (copyTypes.includes('copyHeaders')) {
+ items['copyHeaders'] = copyHeadersItem;
+ }
+ // 复制列名和值
+ if (copyTypes.includes('copyHeadersAndData')) {
+ items['copyHeadersAndData'] = copyHeadersAndDataItem;
+ }
+ } else {
+ items['copyData'] = copyDataItem;
}
- return {
- items,
- } as any;
+
+ return { items } as any;
};
return (
@@ -143,7 +188,7 @@ const SpreadSheet: React.FC = forwardRef(
: columns?.[index as number];
return `${title}`;
}}
- data={getData()}
+ data={getShowData()}
mergeCells={getMergeCells()}
cell={getCell()}
readOnly
diff --git a/src/utils/copy.tsx b/src/utils/copy.tsx
index 896deb616..ac7a4e0bc 100644
--- a/src/utils/copy.tsx
+++ b/src/utils/copy.tsx
@@ -60,7 +60,10 @@ export default class CopyUtils {
let succeeded;
try {
- succeeded = document.execCommand('copy');
+ // 浏览器兼容性处理,当前语法已废弃,延迟处理可以保证复制成功
+ setTimeout(() => {
+ succeeded = document.execCommand('copy');
+ });
} catch (err) {
succeeded = false;
}