[英]In reactJS, how to copy text to clipboard?
我正在使用 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()
}
如果您想以編程方式將數據寫入剪貼板,請在按鈕上使用這個簡單的內聯 onClick function。
onClick={() => {navigator.clipboard.writeText(this.state.textToCopy)}}
我個人認為不需要圖書館。 查看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>
);
}
您可以在不需要外部庫的情況下完成此操作,例如:在按鈕內
<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>
希望這可以幫助。
您絕對應該考慮使用 package 像上面的@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'))
最簡單的方法是使用react-copy-to-clipboard
npm package。
您可以使用以下命令安裝它
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
這是一個正在運行的小提琴。
帶有反應鈎子的最佳解決方案,不需要外部庫
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.clip board 的更多文檔 ,navigator.clipboard 文檔navigotor.clipboard 受到大量瀏覽器的支持查看此處支持的瀏覽器
剪貼板在 2021 年得到主流瀏覽器的良好支持。 一種方法是首先將副本構建到剪貼板 function ,然后使用onClick
事件處理程序調用它。
function copy(text){
navigator.clipboard.writeText(text)
}
為了防止硬編碼,假設string
被分配給名為someText
的變量
<span onClick={() => copy(someText)}>
{someText}
</span>
您可以使用事件剪貼板數據收集方法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
我采取了與上述一些方法非常相似的方法,但我認為它更具體一些。 在這里,父組件將 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>
);
};
您的代碼應該可以完美運行,我以同樣的方式使用它。 僅確保如果單擊事件是從彈出屏幕(如引導模式或其他內容)中觸發的,則創建的元素必須在該模式中,否則不會復制。 您始終可以在該模式中提供元素的 id(作為第二個參數)並使用 getElementById 檢索它,然后 append 將新創建的元素添加到該元素而不是文檔。 像這樣的東西:
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);
}
const copyToClipboard = e => {
navigator.clipboard.writeText(window.location.toString())
}
<button copyToClipboard={shareLink}>
Click to copy current url to clipboard
</button>
這對我有用:
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])
簡單的答案將是
navigator.clipboard.writeText("值")
使用此命令將您的值傳遞給 function
var promise = navigator.clipboard.writeText(newClipText)
對於那些試圖從 DIV 而不是文本字段 select 的人,這里是代碼。 該代碼是不言自明的,但如果您想了解更多信息,請在此處評論:
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)}
/>
);
}
根據他們的文檔,navigator.clipboard 在 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"/>
)
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>
)
}
}
您可以簡單地使用npm包copy-to-clipboard
。 查看以下示例,將文本復制到剪貼板。 這是該示例的逐步說明。
import React, { Component } from 'react';
import copy from "copy-to-clipboard";
class App extends Component {
constructor() {
super();
this.state = {
textToCopy: "Copy to Clipboard Demo!",
btnText: "Copy to Clipboard"
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleCopy = this.handleCopy.bind(this);
}
handleInputChange(e) {
this.setState({
textToCopy: e.target.value,
btnText: "Copy to Clipboard"
});
}
handleCopy() {
copy(this.state.textToCopy);
this.setState({ btnText: "Copied!" });
}
render() {
const { textToCopy, btnText } = this.state;
return (
<div>
<h4>Clue Mediator - Copy to Clipboard</h4>
<textarea value={textToCopy} onChange={this.handleInputChange} />
<br />
<br />
<button onClick={this.handleCopy} disabled={btnText === "Copied!"}>
{btnText}
</button>
</div>
);
}
}
為了更好地理解,我還准備了一個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;
這是按鈕的樣子:
當你點擊它時:
資料來源: https://fwuensche.medium.com/react-button-to-copy-to-clipboard-75ef5ecdc708
無需安裝第三方軟件包。 我盡量保持簡單。 這對我來說效果很好。
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>
)
}
如果你想 select 從 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
在反應功能組件內部。 創建一個名為 handleCopy 的 function:
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 也有一種很酷的方法來做到這一點,其中包括工具提示: 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 並敬酒 ZC7A628CBA22E28EB17B5F5C6AE2A266AZ:
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>
</>
)
}
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>
const handleCopy = async () => {
let copyText = document.getElementById('input') as HTMLInputElement;
copyText.select();
document.execCommand('copy');
};
return (
<TextField
variant="outlined"
value={copyText}
id="input"
/>
);
這對我來說是工作。
這是我的代碼:
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>
您還可以使用以下代碼在 function 組件或無狀態組件中使用反應掛鈎: PS:確保使用以下命令通過 npm/yarn 安裝 useClippy:npm install use-clippy 或 yarn add 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>
);
}
您可以在元素內使用 useRef 到 select 文本,然后將其復制到剪貼板
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> )
}
受@nate 的回答啟發,我創建了一個withCopyText
反應鈎子。 並且,添加了帶有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>
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
首先創建 BTN,然后添加這個 onClick:
onClick={() => navigator.clipboard.writeText(textState)}
或者
onClick={() => navigator.clipboard.writeText('Your text for copy')}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.