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

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

最简单的方法是使用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

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

你绝对应该考虑使用上面建议的@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'))

我个人认为没有必要为此建立一个图书馆。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>
);
}

你可以使用事件clipboardData收集方法e.clipboardData.setData(type, content)

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

...


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

干杯!

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

你的代码应该工作完美,我用同样的方式。只需要确保如果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);
}

对于那些试图从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)}
/>
);
}

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

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

我采取了和上面一些非常相似的方法,但我认为它更具体一些。在这里,父组件将作为道具传递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>
);
};
import React, { Component } from 'react';


export default class CopyTextOnClick extends Component {
copyText = () => {
this.refs.input.select();


document.execCommand('copy');


return false;
}


render () {
const { text } = this.state;


return (
<button onClick={ this.copyText }>
{ text }


<input
ref="input"
type="text"
defaultValue={ text }
style=\{\{ position: 'fixed', top: '-1000px' }} />
</button>
)
}
}

这是我的代码:

import React from 'react'


class CopyToClipboard extends React.Component {


textArea: any


copyClipBoard = () => {
this.textArea.select()
document.execCommand('copy')
}


render() {
return (
<>
<input style=\{\{display: 'none'}} value="TEXT TO COPY!!" type="text" ref={(textarea) => this.textArea = textarea}  />
<div onClick={this.copyClipBoard}>
CLICK
</div>
</>


)
}
}


export default CopyToClipboard
<input
value={get(data, "api_key")}
styleName="input-wrap"
title={get(data, "api_key")}
ref={apikeyObjRef}
/>
<div
onClick={() => {
apikeyObjRef.current.select();
if (document.execCommand("copy")) {
document.execCommand("copy");
}
}}
styleName="copy"
>
复制
</div>

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

定义一个方法

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

调用那个方法

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

如果希望从DIV而不是文本字段中进行选择,下面是代码。“代码”是需要复制的值

import React from 'react'
class CopyToClipboard extends React.Component {


copyToClipboard(code) {
var textField = document.createElement('textarea')
textField.innerText = code
document.body.appendChild(textField)
textField.select()
document.execCommand('copy')
textField.remove()
}
render() {
return (
<div onClick={this.copyToClipboard.bind(this, code)}>
{code}
</div>


)
}
}


export default CopyToClipboard

找到了最好的方法。我是说最快的方法:w3school

https://www.w3schools.com/howto/howto_js_copy_clipboard.asp

在react函数组件中。创建名为handleCopy的函数:

function handleCopy() {
// get the input Element ID. Save the reference into copyText
var copyText = document.getElementById("mail")
// select() will select all data from this input field filled
copyText.select()
copyText.setSelectionRange(0, 99999)
// execCommand() works just fine except IE 8. as w3schools mention
document.execCommand("copy")
// alert the copied value from text input
alert(`Email copied: ${copyText.value} `)
}


<>
<input
readOnly
type="text"
value="exemple@email.com"
id="mail"
/>
<button onClick={handleCopy}>Copy email</button>


</>

如果不使用React, w3schools也有一个很酷的方法来做到这一点,包括tooltip: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_copy_clipboard2

如果使用React,一个很酷的想法是:使用Toastify来提醒消息。 https://github.com/fkhadra/react-toastify这是一个很容易使用的库。 安装后,你可以修改这一行:

 alert(`Email copied: ${copyText.value} `)

比如:

toast.success(`Email Copied: ${copyText.value} `)

如果你想使用它,不要忘记安装toastify。导入ToastContainer,同时也导入css:

import { ToastContainer, toast } from "react-toastify"
import "react-toastify/dist/ReactToastify.css"

并将烤面包的容器放入里面返回。

import React from "react"


import { ToastContainer, toast } from "react-toastify"
import "react-toastify/dist/ReactToastify.css"




export default function Exemple() {
function handleCopy() {
var copyText = document.getElementById("mail")
copyText.select()
copyText.setSelectionRange(0, 99999)
document.execCommand("copy")
toast.success(`Hi! Now you can: ctrl+v: ${copyText.value} `)
}


return (
<>
<ToastContainer />
<Container>
<span>E-mail</span>
<input
readOnly
type="text"
value="myemail@exemple.com"
id="mail"
/>
<button onClick={handleCopy}>Copy Email</button>
</Container>
</>
)
}

你可以做到这一点,而不需要一个外部库,例如:在一个按钮

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

对于ie11和更老的浏览器,你可能需要稍微改变一下代码,这里有一个例子:

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

希望这能有所帮助。

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

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

 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>

导航器。剪贴板不工作在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"/>
)

使用此命令将值传递给函数

var promise = navigator.clipboard.writeText(newClipText)
你也可以在函数组件或无状态组件中使用react钩子: PS:确保你通过npm/yarn使用这个命令安装useClippy: NPM安装使用clippy或 纱线添加use-clippy

import React from 'react';
import useClippy from 'use-clippy';


export default function YourComponent() {


// clipboard is the contents of the user's clipboard.
// setClipboard('new value') wil set the contents of the user's clipboard.


const [clipboard, setClipboard] = useClippy();


return (
<div>


{/* Button that demonstrates reading the clipboard. */}
<button
onClick={() => {
alert(`Your clipboard contains: ${clipboard}`);
}}
>
Read my clipboard
</button>


{/* Button that demonstrates writing to the clipboard. */}
<button
onClick={() => {
setClipboard(`Random number: ${Math.random()}`);
}}
>
Copy something
</button>
</div>
);
}

这对我来说很有用:

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])

您可以使用useRef选择元素中的文本,然后将其复制到剪贴板

import React, { useRef } from "react";


const Comp = () => {
const copyTxt = useRef();


const handleCopyTxt = () => {
let txtDiv = copyTxt.current;
if (document.selection) {
// IE
var range = document.body.createTextRange();
range.moveToElementText(txtDiv);
range.select();
} else if (window.getSelection) {
// other browsers
var range = document.createRange();
range.selectNode(txtDiv);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
}
document.execCommand("copy");
}


return ( <div ref={copyTxt} > some text to copied </div> )
}

最简单的答案就是

navigator.clipboard.writeText(“value")

剪贴板是2021年将被主流浏览器广泛支持。一种方法是首先构建一个拷贝到剪贴板函数,然后使用onClick事件处理程序调用它。

function copy(text){
navigator.clipboard.writeText(text)
}

为了防止硬编码,让我们假设string被赋值给一个名为someText的变量

<span onClick={() => copy(someText)}>
{someText}
</span>

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

钩子意味着它可以跨许多组件重用,而无需重复代码。具体实现请参见示例组件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 };


针对React开发者

 const preventCopyPasteBody = (state) => {
document.addEventListener(state, (evt) => {
if (evt.target.id === 'body') {
evt.preventDefault();
return false;
}
return false;
}, false);
}


preventCopyPasteBody ("contextmenu")
preventCopyPasteBody ("copy")
preventCopyPasteBody ("paste")
preventCopyPasteBody ("cut")


<Typography id="body" variant="body1"  component="div" className={classes.text} style=\{\{ fontSize: fontSize }}>{story}</Typography>

使用材质UI完全工作的React组件

为了更好地理解,我还准备了一个CodeSandbox。希望这能有所帮助。

import { useState } from "react";
import { IconButton, Snackbar } from "@mui/material";
import ShareIcon from "@mui/icons-material/Share";


const CopyToClipboardButton = () => {
const [open, setOpen] = useState(false);


const handleClick = () => {
setOpen(true);
navigator.clipboard.writeText(window.location.toString());
};


return (
<>
<IconButton onClick={handleClick} color="primary">
<ShareIcon />
</IconButton>
<Snackbar
message="Copied to clibboard"
anchorOrigin=\{\{ vertical: "top", horizontal: "center" }}
autoHideDuration={20000}
onClose={() => setOpen(false)}
open={open}
/>
</>
);
};


export default CopyToClipboardButton;

下面是按钮的样子:

enter image description here

当你点击它时:

enter image description here

来源:https://fwuensche.medium.com/react-button-to-copy-to-clipboard-75ef5ecdc708

const handleCopy = async () => {
let copyText = document.getElementById('input') as HTMLInputElement;
copyText.select();
document.execCommand('copy');
};


return (
<TextField
variant="outlined"
value={copyText}
id="input"
/>
);

这是我的工作。

make a componant as follows :-


//react functional componant


import React, { useState } from "react";


function CopyToClipboard(props) {
const [copied, setCopied] = useState("copy");
return (
<div
className="font-medium mr-4 text-green-700 cursor-pointer"
onClick={() => {
navigator.clipboard.writeText(props.text);
setCopied("copied");
}}>
{copied}
</div>
);
}


export default CopyToClipboard;


//then use this componant anywhere


<CopyToClipboard text={"text you want to copy"}></CopyToClipboard>


//it will give a text saying "copy"`enter code here` and after clicking on that text, text provided with props will get copied
                    

                  

无需安装第三方软件包。我尽量让它简单。这对我来说很有效。

import React, { useState } from "react"
function MyApp() {
const [copySuccess, setCopySuccess] = useState(null);
const copyToClipBoard = async copyMe => {
try {
await navigator.clipboard.writeText(copyMe);
setCopySuccess('Copied!');
}
catch (err) {
setCopySuccess('Failed to copy!');
}
};
     

return (
<button onClick={(e) => copyToClipBoard(what you want to copy goes here)} >
My button
</button>
)
}

首先创建BTN,然后添加这个onClick:

onClick={() =>  navigator.clipboard.writeText(textState)}

onClick={() =>  navigator.clipboard.writeText('Your text for copy')}