Javascript 在reactJS中,如何将文本复制到剪贴板?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39501289/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 22:38:05  来源:igfitidea点击:

In reactJS, how to copy text to clipboard?

javascriptreactjsclipboard

提问by Duke Dougal

I'm using ReactJS and when a user clicks a link I want to copy some text to the clipboard.

我正在使用 ReactJS,当用户单击链接时,我想将一些文本复制到剪贴板。

I am using Chrome 52 and I do not need to support any other browsers.

我使用的是 Chrome 52,不需要支持任何其他浏览器。

I can't see why this code does not result in the data being copied to the clipboard. (the origin of the code snippet is from a Reddit post).

我不明白为什么这段代码不会导致数据被复制到剪贴板。(代码片段的来源来自 Reddit 帖子)。

Am I doing this wrong? Can anyone suggest is there a "correct" way to implement copy to clipboard using reactjs?

我这样做错了吗?任何人都可以建议是否有一种“正确”的方法来使用 reactjs 实现复制到剪贴板?

copyToClipboard = (text) => {
  console.log('text', text)
  var textField = document.createElement('textarea')
  textField.innerText = text
  document.body.appendChild(textField)
  textField.select()
  document.execCommand('copy')
  textField.remove()
}

回答by Nate

I personally don't see the need for a library for this. Looking at http://caniuse.com/#feat=clipboardit's pretty widely supported now, however you can still do things like checking to see if the functionality exists in the current client and simply hide the copy button if it doesn't.

我个人认为没有必要为此建立一个图书馆。查看http://caniuse.com/#feat=clipboard它现在得到了广泛的支持,但是您仍然可以执行一些操作,例如检查当前客户端中是否存在该功能,如果不存在,则只需隐藏复制按钮。

import React from 'react';

class CopyExample extends React.Component {

  constructor(props) {
    super(props);

    this.state = { copySuccess: '' }
  }

  copyToClipboard = (e) => {
    this.textArea.select();
    document.execCommand('copy');
    // This is just personal preference.
    // I prefer to not show the the whole text area selected.
    e.target.focus();
    this.setState({ copySuccess: 'Copied!' });
  };

  render() {
    return (
      <div>
        {
         /* Logical shortcut for only displaying the 
            button if the copy command exists */
         document.queryCommandSupported('copy') &&
          <div>
            <button onClick={this.copyToClipboard}>Copy</button> 
            {this.state.copySuccess}
          </div>
        }
        <form>
          <textarea
            ref={(textarea) => this.textArea = textarea}
            value='Some text to copy'
          />
        </form>
      </div>
    );
  }

}

export default CopyExample;

Update: Rewritten using React Hooks in React 16.7.0-alpha.0

更新:在 React 16.7.0-alpha.0 中使用 React Hooks 重写

import React, { useRef, useState } from 'react';

export default function CopyExample() {

  const [copySuccess, setCopySuccess] = useState('');
  const textAreaRef = useRef(null);

  function copyToClipboard(e) {
    textAreaRef.current.select();
    document.execCommand('copy');
    // This is just personal preference.
    // I prefer to not show the the whole text area selected.
    e.target.focus();
    setCopySuccess('Copied!');
  };

  return (
    <div>
      {
       /* Logical shortcut for only displaying the 
          button if the copy command exists */
       document.queryCommandSupported('copy') &&
        <div>
          <button onClick={copyToClipboard}>Copy</button> 
          {copySuccess}
        </div>
      }
      <form>
        <textarea
          ref={textAreaRef}
          value='Some text to copy'
        />
      </form>
    </div>
  );
}

回答by Gary Vernon Grubb

Use this simple inline onClick function on a button if you want to programatically write data to the clipboard.

如果您想以编程方式将数据写入剪贴板,请在按钮上使用这个简单的内联 onClick 函数。

onClick={() => {navigator.clipboard.writeText(this.state.textToCopy)}}

回答by Drew Schuster

You should definitely consider using a package like @Shubham above is advising, but I created a working codepen based on what you described: http://codepen.io/dtschust/pen/WGwdVN?editors=1111. It works in my browser in chrome, perhaps you can see if there's something I did there that you missed, or if there's some extended complexity in your application that prevents this from working.

您绝对应该考虑使用上面建议的@Shubham 之类的包,但我根据您的描述创建了一个工作代码笔:http://codepen.io/dtschust/pen/WGwdVN?editors=1111 。它可以在我的 chrome 浏览器中运行,也许您可​​以查看我是否在那里做了一些您遗漏的事情,或者您的应用程序中是否有一些扩展的复杂性阻止了它的工作。

// html
<html>
  <body>
    <div id="container">

    </div>
  </body>
</html>


// js
const Hello = React.createClass({
  copyToClipboard: () => {
    var textField = document.createElement('textarea')
    textField.innerText = 'foo bar baz'
    document.body.appendChild(textField)
    textField.select()
    document.execCommand('copy')
    textField.remove()
  },
  render: function () {
    return (
      <h1 onClick={this.copyToClipboard}>Click to copy some text</h1>
    )
  }
})

ReactDOM.render(
<Hello/>,
  document.getElementById('container'))

回答by Shubham Khatri

The simplest way will be use the react-copy-to-clipboardnpm package.

最简单的方法是使用react-copy-to-clipboardnpm 包。

You can install it with the following command

您可以使用以下命令安装它

npm install --save react react-copy-to-clipboard

Use it in the following manner.

按以下方式使用它。

const App = React.createClass({
  getInitialState() {
    return {value: '', copied: false};
  },


  onChange({target: {value}}) {
    this.setState({value, copied: false});
  },


  onCopy() {
    this.setState({copied: true});
  },


  render() {
    return (
      <div>

          <input value={this.state.value} size={10} onChange={this.onChange} />

        <CopyToClipboard text={this.state.value} onCopy={this.onCopy}>
          <button>Copy</button>
        </CopyToClipboard>

                <div>
        {this.state.copied ? <span >Copied.</span> : null}
                </div>
        <br />

        <input type="text" />

      </div>
    );
  }
});

ReactDOM.render(<App />, document.getElementById('container'));

A detailed explanation is provided at the following link

在以下链接中提供了详细说明

https://www.npmjs.com/package/react-copy-to-clipboard

https://www.npmjs.com/package/react-copy-to-clipboard

Here is a running fiddle.

这是一个正在运行的小提琴

回答by Damian Przygodzki

Why do not use just event clipboardData collection method e.clipboardData.setData(type, content)?

为什么不只使用事件剪贴板数据收集方法e.clipboardData.setData(type, content)

In my opinion is the most streightforward method to achieve pushing smth inside clipboard, check this out (i've used that to modify data while native copying action):

在我看来,这是实现在剪贴板内推送 smth 的最直接的方法,检查一下(我已经使用它在本机复制操作时修改数据):

...

handleCopy = (e) => {
    e.preventDefault();
    e.clipboardData.setData('text/plain', 'Hello, world!');
}

render = () =>
    <Component
        onCopy={this.handleCopy}
    />

I followed that path: https://developer.mozilla.org/en-US/docs/Web/Events/copy

我遵循了这条路径:https: //developer.mozilla.org/en-US/docs/Web/Events/copy

Cheers!

干杯!

EDIT: For testing purposes, i've added codepen: https://codepen.io/dprzygodzki/pen/ZaJMKb

编辑:出于测试目的,我添加了 codepen:https://codepen.io/dprzygodzki/pen/ZaJMKb

回答by jerryurenaa

Why use you need an npm package when you can get all within a single button like this

当您可以在这样的单个按钮中获取所有内容时,为什么要使用 npm 包

<button 
  onClick={() =>  navigator.clipboard.writeText('Copy this text to clipboard')}
>
  Copy
</button>

I hope this helps @jerryurenaa

我希望这有助于@jerryurenaa

回答by Kupi

Your code should work perfectly, I use it the same way. Only make sure that if the click event is triggered from within a pop up screen like a bootstrap modal or something, the created element has to be within that modal otherwise it won't copy. You could always give the id of an element within that modal (as a second parameter) and retrieve it with getElementById, then append the newly created element to that one instead of the document. Something like this:

您的代码应该可以完美运行,我以同样的方式使用它。仅确保如果单击事件是从弹出屏幕(如引导程序模态或其他东西)内触发的,则创建的元素必须在该模态内,否则不会复制。您始终可以在该模式中提供元素的 id(作为第二个参数)并使用 getElementById 检索它,然后将新创建的元素附加到该元素而不是文档中。像这样的东西:

copyToClipboard = (text, elementId) => {
  const textField = document.createElement('textarea');
  textField.innerText = text;
  const parentElement = document.getElementById(elementId);
  parentElement.appendChild(textField);
  textField.select();
  document.execCommand('copy');
  parentElement.removeChild(textField);
}

回答by tjgragg

I've taken a very similar approach as some of the above, but made it a little more concrete, I think. Here, a parent component will pass the url (or whatever text you want) as a prop.

我采取了与上述一些非常相似的方法,但我认为它更具体一些。在这里,父组件会将 url(或您想要的任何文本)作为道具传递。

import * as React from 'react'

export const CopyButton = ({ url }: any) => {
  const copyToClipboard = () => {
    const textField = document.createElement('textarea');
    textField.innerText = url;
    document.body.appendChild(textField);
    textField.select();
    document.execCommand('copy');
    textField.remove();
  };

  return (
    <button onClick={copyToClipboard}>
      Copy
    </button>
  );
};

回答by connect2Coder

For those people who are trying to select from the DIV instead of the text field, here is the code. The code is self-explanatory but comment here if you want more information:

对于那些试图从 DIV 而不是文本字段中进行选择的人,这里是代码。该代码是不言自明的,但如果您想了解更多信息,请在此处发表评论:

     import React from 'react';
     ....

    //set ref to your div
          setRef = (ref) => {
            // debugger; //eslint-disable-line
            this.dialogRef = ref;
          };

          createMarkeup = content => ({
            __html: content,
          });

    //following function select and copy data to the clipboard from the selected Div. 
   //Please note that it is only tested in chrome but compatibility for other browsers can be easily done

          copyDataToClipboard = () => {
            try {
              const range = document.createRange();
              const selection = window.getSelection();
              range.selectNodeContents(this.dialogRef);
              selection.removeAllRanges();
              selection.addRange(range);
              document.execCommand('copy');
              this.showNotification('Macro copied successfully.', 'info');
              this.props.closeMacroWindow();
            } catch (err) {
              // console.log(err); //eslint-disable-line
              //alert('Macro copy failed.');
            }
          };

              render() {
                    return (
                        <div
                          id="macroDiv"
                          ref={(el) => {
                            this.dialogRef = el;
                          }}
                          // className={classes.paper}
                          dangerouslySetInnerHTML={this.createMarkeup(this.props.content)}
                        />
                    );
            }

回答by jasonleonhard

Here's another use case, if you would like to copy the current url to your clipboard:

这是另一个用例,如果您想将当前 url 复制到剪贴板:

Define a method

定义方法

const copyToClipboard = e => {
  navigator.clipboard.writeText(window.location.toString())
}

Call that method

调用那个方法

<button copyToClipboard={shareLink}>
   Click to copy current url to clipboard
</button>