我使用的是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()
}

当前回答

我个人认为没有必要为此建立一个图书馆。看看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 hook重写

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

其他回答

受@nate回答的启发,我创建了一个withCopyText反应钩子。并且,添加了navigator.clipboard.writeText支持execCommand回退。

钩子意味着它可以跨许多组件重用,而无需重复代码。有关实现,请参阅示例组件CopyText。

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

const withCopyText = (textElementRef) => {
  if (!textElementRef) throw 'withCopyText: ref is required';

  const [copyStatus, setCopyStatus] = useState('');
  const [support, setSupport] = useState({
    navigatorClipboard: !!navigator.clipboard,
    exec: !!document.queryCommandSupported('copy'),
  });

  const copyToClipboard = (e) => {
    if ('' !== copyStatus) {
      setCopyStatus('');
      await new Promise((resolve) => setTimeout(resolve, 200));
    }

    // clipboard.writeText has wide but not 100% support
    // https://caniuse.com/?search=writeText
    if (support.navigatorClipboard) {
      try {
        navigator.clipboard.writeText(textElementRef.current.value);
        return setCopyStatus('success');
      } catch (e) {
        setSupport({ ...support, navigatorClipboard: false });
      }
    }
    // execCommand has > 97% support but is deprecated, use it as a fallback
    // https://caniuse.com/?search=execCommand
    // https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
    if (!support.navigatorClipboard) {
      try {
        textElementRef.current.select();
        document.execCommand('copy');
        e.target.focus();
        setCopyStatus('success');
      } catch (e) {
        setSupport({ ...support, exec: false });
        return setCopyStatus('fail');
      }
    }
  };

  return {
    copyStatus,
    copyToClipboard,
    support: Object.values(support).includes(true),
  };
};

const CopyText = ({ text }) => {
  const textElementRef = useRef(null);

  const { copyStatus, copyToClipboard, support } = withCopyText(textElementRef);

  return (
    <span>
      {support && <button onClick={copyToClipboard}>Copy</button>}
      {'success' === copyStatus && <span>Copied to clipboard!</span>}
      {'fail' === copyStatus && <span>Sorry, copy to clipboard failed</span>}
      <input type="text" ref={textElementRef} value={text} readOnly={true} />
    </span>
  );
};

export { CopyText, withCopyText };

你的代码应该工作完美,我用同样的方式。只需要确保如果click事件是从弹出屏幕中触发的,比如bootstrap模式或其他,创建的元素必须在该模式中,否则它不会被复制。您总是可以给出该模式中元素的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);
}

您可以使用事件clipboardData收集方法e.clipboardData。setData(类型、内容)。

在我看来,这是实现在剪贴板内推送一些东西的最直接的方法,看看这个(我用它来修改数据,而本地复制动作):

...

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

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

我选择了这个路径:https://developer.mozilla.org/en-US/docs/Web/Events/copy

干杯!

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

react钩子的最佳解决方案,不需要外部库

import React, { useState } from 'react'; const MyComponent = () => { const [copySuccess, setCopySuccess] = useState(''); // your function to copy here const copyToClipBoard = async copyMe => { try { await navigator.clipboard.writeText(copyMe); setCopySuccess('Copied!'); } catch (err) { setCopySuccess('Failed to copy!'); } }; return ( <div> <Button onClick={() => copyToClipBoard('some text to copy')}> Click here to copy </Button> // after copying see the message here {copySuccess} </div> ) }

查看关于导航器的进一步文档。弹夹板,导航器。剪贴板文件 navigotor。剪贴板是由大量浏览器支持的,看这里支持的浏览器

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

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

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

这是一把移动小提琴。