本文基于react項目實作。
起因
接了一個需求,要求實作點選頁面上的一個按鈕,複制某個表格資料,然後ctrl+V到Excel表格中。
思考
其實我覺着這個功能用導出Excel的方式實作不就好了麼。不過本着好奇的心思,還是試着做做看吧。
首先,點選按鈕的時候要拿到要複制的資料。最初是想通過擷取DOM元素的方式來取得表格,可是這樣的話,得到的就是含有html标簽的一堆字元串。那麼隻能自己來拼裝資料了。我把表格部分的資料通過複制、黏貼到編輯器看下他是什麼,結果如下圖:
而頁面上的表格是這樣的:
對比來看:跟頁面上的表格差别不大。
其次,要把資料組裝好之後,要通過JS的方式放到剪切闆中。這個有點難度了。通過查資料下面這種方式可以改變剪切闆的内容。
document.addEventListener("copy", (event) => {
if (copyEvent) {
if (event.clipboardData || event.originalEvent) {
var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
const selection = "好激動12312412\nhahahha";
clipboardData.setData('text/plain', selection.toString());
event.preventDefault();
}
}
});
那麼,問題來了,這裡是通過監聽copy事件來改變剪切闆的内容的,但是我們點選按鈕到複制到Excel裡面,這過程中并沒有觸發ctrl+C的操作啊?
那麼隻能點選按鈕的時候來觸發了。
document.execCommand('copy')
可以實作。
然後,由于是在document上做的監聽,那麼頁面上所有的複制操作都被攔截了,換成我們拼接的内容啦。顯然這不是我們想要的。于是我想到了開關,在點選按鈕的時候打開開關,然後觸發copy事件,在監聽事件中判斷開關狀态,這樣就能過濾掉其他位置的複制的操作了。
實作
• 先準備環境、資料
import { Button, Table } from 'antd';
import { useEffect } from 'react'
import './App.css';
const dataSource = [
{
key: '1',
name: '胡彥斌',
age: 32,
address: '西湖區湖底公園1号',
},
{
key: '2',
name: '胡彥祖',
age: 42,
address: '西湖區湖底公園1号',
},
];
const columns = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年齡',
dataIndex: 'age',
key: 'age',
},
{
title: '住址',
dataIndex: 'address',
key: 'address',
},
]
const btnClick = () => {
}
function App() {
return (
<div className="App">
<header className="App-header">
<Button type="primary" onClick={btnClick}>複制</Button>
<Table dataSource={dataSource} columns={columns} />
</header>
</div>
);
}
export default App;
• 監聽copy事件,點選按鈕的時候觸發copy事件
const btnClick = () => {
document.execCommand('copy')
}
useEffect(() => {
document.addEventListener("copy", (event) => {
if (event.clipboardData || event.originalEvent) {
var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
const selection = "好激動12312412\nhahahha";
clipboardData.setData('text/plain', selection.toString());
event.preventDefault();
copyEvent = false
}
});
}, []);
• 添加開關、拼接資料
let copyEvent = false // 開關
const btnClick = () => {
copyEvent = true
document.execCommand('copy')
}
useEffect(() => {
document.addEventListener("copy", (event) => {
if (copyEvent) {
if (event.clipboardData || event.originalEvent) {
var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
// 拼接資料
const first = columns.map(item=>item.title).join('\t')
const sec = dataSource.map(item=> `${item.name}\t${item.age} \t${item.address}`).join('\n')
const selection = `${first}\n${sec}`
clipboardData.setData('text/plain', selection.toString());
event.preventDefault();
copyEvent = false // 關掉開關
}
}
});
}, []);
\t是制表符,在Excel中就是單元格分隔。\n是換行符,對應Excel就是不同行。
複制到Excel中的效果:
完整代碼
import { Button, Table } from 'antd';
import { useEffect } from 'react'
import './App.css';
const dataSource = [
{
key: '1',
name: '胡彥斌',
age: 32,
address: '西湖區湖底公園1号',
},
{
key: '2',
name: '胡彥祖',
age: 42,
address: '西湖區湖底公園1号',
},
];
const columns = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年齡',
dataIndex: 'age',
key: 'age',
},
{
title: '住址',
dataIndex: 'address',
key: 'address',
},
]
let copyEvent = false // 開關
const btnClick = () => {
copyEvent = true
document.execCommand('copy')
}
function App() {
useEffect(() => {
document.addEventListener("copy", (event) => {
if (copyEvent) {
if (event.clipboardData || event.originalEvent) {
var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
// 拼接資料
const first = columns.map(item=>item.title).join('\t')
const sec = dataSource.map(item=> `${item.name}\t${item.age} \t${item.address}`).join('\n')
const selection = `${first}\n${sec}`
clipboardData.setData('text/plain', selection.toString());
event.preventDefault();
copyEvent = false // 關掉開關
}
}
});
}, []);
return (
<div className="App">
<header className="App-header">
<Button type="primary" onClick={btnClick}>複制</Button>
<Table dataSource={dataSource} columns={columns} />
</header>
</div>
);
}
export default App;
參考
• execCommand
• JS設定擷取剪切闆内容