天天看點

通過JS實作點選複制頁面表格到Excel

本文基于react項目實作。

起因

接了一個需求,要求實作點選頁面上的一個按鈕,複制某個表格資料,然後ctrl+V到Excel表格中。

思考

其實我覺着這個功能用導出Excel的方式實作不就好了麼。不過本着好奇的心思,還是試着做做看吧。

首先,點選按鈕的時候要拿到要複制的資料。最初是想通過擷取DOM元素的方式來取得表格,可是這樣的話,得到的就是含有html标簽的一堆字元串。那麼隻能自己來拼裝資料了。我把表格部分的資料通過複制、黏貼到編輯器看下他是什麼,結果如下圖:

通過JS實作點選複制頁面表格到Excel

而頁面上的表格是這樣的:

通過JS實作點選複制頁面表格到Excel

對比來看:跟頁面上的表格差别不大。

其次,要把資料組裝好之後,要通過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中的效果:

通過JS實作點選複制頁面表格到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設定擷取剪切闆内容

繼續閱讀