问题
I'm using ReactJS and when a user clicks a link I want to copy some text to the clipboard.
I am using Chrome 52 and I do not need to support any other browsers.
I can't see why this code does not result in the data being copied to the clipboard. (the origin of the code snippet is from a Reddit post).
Am I doing this wrong? Can anyone suggest is there a "correct" way to implement copy to clipboard using 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()
}
回答1:
I personally don't see the need for a library for this. Looking at http://caniuse.com/#feat=clipboard it's pretty widely supported now, however you can still do things like checking to see if the functionality exists in the current client and simply hide the copy button if it doesn't.
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 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;
Update: Rewritten using React Hooks in React 16.7.0-alpha.0
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 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>
);
}
回答2:
Use this simple inline onClick function on a button if you want to programatically write data to the clipboard.
onClick={() => {navigator.clipboard.writeText(this.state.textToCopy)}}
回答3:
You should definitely consider using a package like @Shubham above is advising, but I created a working codepen based on what you described: http://codepen.io/dtschust/pen/WGwdVN?editors=1111 . It works in my browser in chrome, perhaps you can see if there's something I did there that you missed, or if there's some extended complexity in your application that prevents this from working.
// 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'))
回答4:
The simplest way will be use the react-copy-to-clipboard
npm package.
You can install it with the following command
npm install --save react react-copy-to-clipboard
Use it in the following manner.
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'));
A detailed explanation is provided at the following link
https://www.npmjs.com/package/react-copy-to-clipboard
Here is a running fiddle.
回答5:
Why do not use just event clipboardData collection method e.clipboardData.setData(type, content)
?
In my opinion is the most streightforward method to achieve pushing smth inside clipboard, check this out (i've used that to modify data while native copying action):
...
handleCopy = (e) => {
e.preventDefault();
e.clipboardData.setData('text/plain', 'Hello, world!');
}
render = () =>
<Component
onCopy={this.handleCopy}
/>
I followed that path: https://developer.mozilla.org/en-US/docs/Web/Events/copy
Cheers!
EDIT: For testing purposes, i've added codepen: https://codepen.io/dprzygodzki/pen/ZaJMKb
回答6:
Your code should work perfectly, I use it the same way. Only make sure that if the click event is triggered from within a pop up screen like a bootstrap modal or something, the created element has to be within that modal otherwise it won't copy. You could always give the id of an element within that modal (as a second parameter) and retrieve it with getElementById, then append the newly created element to that one instead of the document. Something like this:
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);
}
回答7:
I've taken a very similar approach as some of the above, but made it a little more concrete, I think. Here, a parent component will pass the url (or whatever text you want) as a prop.
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>
);
};
回答8:
You can simply use the npm package copy-to-clipboard. Look at the below example to copy text to clipboard. Here is the step by step explanation of the example.
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>
);
}
}
回答9:
For those people who are trying to select from the DIV instead of the text field, here is the code. The code is self-explanatory but comment here if you want more information:
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)}
/>
);
}
回答10:
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>
)
}
}
回答11:
here is my code:
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
来源:https://stackoverflow.com/questions/39501289/in-reactjs-how-to-copy-text-to-clipboard