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

当前回答

 copyclip = (item) => {
    var textField = document.createElement('textarea')
    textField.innerText = item
    document.body.appendChild(textField)
    textField.select()
    document.execCommand('copy')
    this.setState({'copy':"Copied"});
    textField.remove()
    setTimeout(() => {
      this.setState({'copy':""});
    }, 1000);
 }

 <span   className="cursor-pointer ml-1" onClick={()=> this.copyclip(passTextFromHere)} >Copy</span> <small>{this.state.copy}</small>

其他回答

您可以使用事件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。剪贴板是由大量浏览器支持的,看这里支持的浏览器

导航器。剪贴板不工作在HTTP连接根据他们的文档。所以你可以检查它是否未定义,并使用document.execCommand('copy')来代替,这个解决方案应该涵盖几乎所有的浏览器

const defaultCopySuccessMessage = 'ID copied!'

const CopyItem = (props) => {
  const { copySuccessMessage = defaultCopySuccessMessage, value } = props

  const [showCopySuccess, setCopySuccess] = useState(false)


  function fallbackToCopy(text) {
    if (window.clipboardData && window.clipboardData.setData) {
      // IE specific code path to prevent textarea being shown while dialog is visible.
      return window.clipboardData.setData('Text', text)
    } else if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
      const textarea = document.createElement('textarea')
      textarea.innerText = text
      // const parentElement=document.querySelector(".up-CopyItem-copy-button")
      const parentElement = document.getElementById('copy')
      if (!parentElement) {
        return
      }
      parentElement.appendChild(textarea)
      textarea.style.position = 'fixed' // Prevent scrolling to bottom of page in MS Edge.
      textarea.select()
      try {
        setCopySuccess(true)
        document.execCommand('copy') // Security exception may be thrown by some browsers.
      } catch (ex) {
        console.log('Copy to clipboard failed.', ex)
        return false
      } finally {
        parentElement.removeChild(textarea)
      }
    }
  }

  const copyID = () => {
    if (!navigator.clipboard) {
      fallbackToCopy(value)
      return
    }
    navigator.clipboard.writeText(value)
    setCopySuccess(true)
  }

  return showCopySuccess ? (
    <p>{copySuccessMessage}</p>
  ) : (
    <span id="copy">
      <button onClick={copyID}>Copy Item </button>
    </span>
  )
}

您可以在任何地方调用和重用该组件

const Sample=()=>(
   <CopyItem value="item-to-copy"/>
)

受@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 };

这对我来说很有用:

const handleCopyLink = useCallback(() => {
    const textField = document.createElement('textarea')
    textField.innerText = url
    document.body.appendChild(textField)
    if (window.navigator.platform === 'iPhone') {
      textField.setSelectionRange(0, 99999)
    } else {
      textField.select()
    }
    document.execCommand('copy')
    textField.remove()
  }, [url])