This paper is implemented based on the React project.

The cause of

I was given a request that the implementation click a button on the page, copy some table data, and then CTRL +V into the Excel table.

thinking

In fact, I think this function can be realized by exporting Excel. But out of curiosity, try it.

First, when you click the button, get the data you want to copy. The original idea is to retrieve the table by retrieving DOM elements, but instead, you end up with a bunch of strings containing HTML tags. So you have to assemble the data yourself. I copied and pasted the data in the table to the editor to see what it looked like. The result is as follows:



The chart on the page looks like this:



In comparison: not much different from the table on the page.

Second, after the data is assembled, it should be put into the clipboard via JS. This is a little difficult. You can change the clipboard content by looking it up.

 document.addEventListener("copy".(event) = > {
      if (copyEvent) {
        if (event.clipboardData || event.originalEvent) {
          var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
          const selection = "So excited 12312412\nhahahha";
          clipboardData.setData('text/plain', selection.toString()); event.preventDefault(); }}});Copy the code

So, here’s the problem. We’re listening for the copy event to change the clipboard contents, but we’re not touching CTRL +C when we click to copy to Excel. So it can only be triggered when you click the button. Document. execCommand(‘copy’) can be implemented. Then, since we’re listening on the Document, all the copying on the page is intercepted, and we’re concatenating the content instead. Obviously that’s not what we want. So I thought of the switch, when clicking the button to turn on the switch, and then trigger the copy event, in the monitoring event to judge the switch state, so that the other location of the copy operation can be filtered out.

implementation

• Prepare the environment and data

import { Button, Table } from 'antd';
import { useEffect } from 'react'
import './App.css';
const dataSource = [
  {
    key: '1'.name: 'Hu Yanbin'.age: 32.address: No. 1 Xihu Lake Bottom Park}, {key: '2'.name: Daniel Hu.age: 42.address: No. 1 Xihu Lake Bottom Park,},];const columns = [
  {
    title: 'name'.dataIndex: 'name'.key: 'name'}, {title: 'age'.dataIndex: 'age'.key: 'age'}, {title: 'address'.dataIndex: 'address'.key: 'address',},]const btnClick = () = >{}function App() {
  return (
    <div className="App">
      <header className="App-header">
        <Button type="primary" onClick={btnClick}>copy</Button>
        <Table dataSource={dataSource} columns={columns} />
      </header>
    </div>
  );
}
export default App;
Copy the code

• Listen for copy events. Copy events are triggered when a button is clicked

const btnClick = () = > {
  document.execCommand('copy')
}
  useEffect(() = > {
    document.addEventListener("copy".(event) = > {
        if (event.clipboardData || event.originalEvent) {
          var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
          const selection = "So excited 12312412\nhahahha";
          clipboardData.setData('text/plain', selection.toString());
          event.preventDefault();
          copyEvent = false}}); } []);Copy the code

• Add switches and splice data

let copyEvent = false / / switch
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);
          // Splice data
          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 // Turn off the switch}}}); } []);Copy the code

\t is a TAB character, which in Excel is cell separation. \n is a newline character, which corresponds to Excel.

Effects copied to Excel:

The complete code

import { Button, Table } from 'antd';
import { useEffect } from 'react'
import './App.css';
const dataSource = [
  {
    key: '1'.name: 'Hu Yanbin'.age: 32.address: No. 1 Xihu Lake Bottom Park}, {key: '2'.name: Daniel Hu.age: 42.address: No. 1 Xihu Lake Bottom Park,},];const columns = [
  {
    title: 'name'.dataIndex: 'name'.key: 'name'}, {title: 'age'.dataIndex: 'age'.key: 'age'}, {title: 'address'.dataIndex: 'address'.key: 'address',},]let copyEvent = false / / switch
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);
          // Splice data
          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 // Turn off the switch}}}); } []);return (
    <div className="App">
      <header className="App-header">
        <Button type="primary" onClick={btnClick}>copy</Button>
        <Table dataSource={dataSource} columns={columns} />
      </header>
    </div>
  );
}
export default App;
Copy the code

reference

• execCommand • JS sets to get clipboard content