我使用的是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()
}
最简单的方法是使用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
这是一把移动小提琴。
受@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 };
导航器。剪贴板不工作在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"/>
)