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

IT技术 javascript reactjs clipboard
2021-01-21 04:39:10

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

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

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

我这样做错了吗?任何人都可以建议是否有一种“正确”的方法来使用 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()
}
6个回答

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

onClick={() => {navigator.clipboard.writeText(this.state.textToCopy)}}
似乎它在 2018 caniuse.com/#search=clipboard 中对主要浏览器的支持很好
2021-03-16 04:39:10
最适合我的用例,要复制的文本实际上不在页面上。谢谢
2021-03-24 04:39:10
由于我被困在这个(在 Chrome 上),navigator.clipboard只有当您的页面从安全来源(HTTPS 或本地主机)加载时才有效。如果需要,您可以检查window.isSecureContext
2021-03-28 04:39:10
navigator.clipboard 不支持所有浏览器
2021-04-10 04:39:10
根据您提供的链接,它似乎只在 safari 中完全支持...
2021-04-12 04:39:10

我个人认为不需要为此建立图书馆。查看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 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;

更新:在 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 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>
  );
}
我收到此typescript错误: Property 'select' does not exist on type 'never'
2021-03-20 04:39:10
只是为了记录:唯一的问题是,如果您尝试复制页面上某些文本元素中尚未存在的文本,则需要破解一组 DOM 元素,设置文本,复制它,并清理它。这是非常小的东西的大量代码。通常我会同意不应该鼓励开发人员不断安装库。
2021-03-22 04:39:10
对于这个特定问题,文本已经在页面上的一个元素中。什么情况下会出现页面上有可见文本但您要复制但不在元素中的情况?这是一个完全不同的问题,我很乐意提供解决方案。你不需要用 react 破解任何东西,你只需要在你的渲染函数中提供一个隐藏的元素,它也包含文本。无需特别创建元素。
2021-03-27 04:39:10
我得到 TypeError: textAreaRef.current.select is not a function
2021-04-01 04:39:10
2021-04-04 04:39:10

您无需外部库即可完成此操作,例如:在按钮内

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

对于 Internet Explorer 11 和更旧的浏览器,您可能需要稍微更改代码,这是一个示例:

<button 
  onClick={() =>  window.clipboardData.setData("Text", 'Copy this text to clipboard')}>
 Copy
</button>

希望这可以帮助。

我更新了答案以支持旧浏览器!感谢您的评论。
2021-03-18 04:39:10
顺便说一句最好的要求
2021-03-19 04:39:10
我收到以下错误: TypeError: Cannot read property 'setData' of undefined
2021-03-23 04:39:10
第二个示例仅适用于旧浏览器,例如:Internet Explorer 11。对于新浏览器,请使用第一个示例。
2021-03-24 04:39:10

您绝对应该考虑使用上面建议的@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'))
这很好,但它不适用于 Android 上的 Chrome (72.0) 和 Android 上的 FF (63.0)。
2021-03-21 04:39:10
如果因为您正在使用 appendChild,无论您之后删除它的速度有多快,这是否会导致屏幕闪烁?
2021-03-22 04:39:10
为什么一个包比你的解决方案更好?
2021-03-24 04:39:10
潜在更好的跨浏览器支持,并在需要修复错误的情况下更多地关注包
2021-04-02 04:39:10
奇迹般有效。是的。我也想知道跨浏览器支持。
2021-04-11 04:39:10

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

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

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

按以下方式使用它。

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'));

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

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

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

如果我想将 html 表的内容复制到剪贴板,如何使用此包?@舒巴姆·哈特里
2021-03-19 04:39:10
您可能需要插入onpaste事件
2021-04-02 04:39:10
如果我需要反向操作,有什么解决方案吗?即作者将从电子邮件中复制文本到 reactjs 应用程序中的文本区域。我不需要保留 html 标签,但是,我只需要保留换行符。
2021-04-09 04:39:10