В реакцииJS, как скопировать текст в буфер обмена?
Я использую ReactJS, и когда пользователь щелкает ссылку, я хочу скопировать некоторый текст в буфер обмена.
Я использую Chrome 52, и мне не нужно поддерживать какие-либо другие браузеры.
Я не понимаю, почему этот код не приводит к копированию данных в буфер обмена. (происхождение фрагмента кода происходит из сообщения Reddit).
Я делаю это неправильно? Может ли кто-нибудь предложить, есть ли "правильный" способ реализовать копию в буфер обмена с помощью реакции?
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
Лично я не вижу необходимости в библиотеке для этого. Глядя на 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 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 Hooks в 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
Вы должны обязательно рассмотреть возможность использования пакета, такого как @Shubham выше, советует, но я создал рабочий код на основе того, что вы описали: http://codepen.io/dtschust/pen/WGwdVN?editors=1111. Он работает в моем браузере в хроме, возможно, вы можете увидеть, есть ли там что-то, что я там пропустил, или если в вашем приложении есть какая-то сложная сложность, которая мешает этому работать.
// 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'))
Ответ 3
Самый простой способ - использовать пакет 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
Вот бег fiddle.
Ответ 4
Используйте эту простую встроенную функцию onClick для кнопки, если вы хотите программно записывать данные в буфер обмена.
onClick={() => {navigator.clipboard.writeText(this.state.textToCopy)}}
Ответ 5
Почему бы не использовать только метод коллекции событий 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
Ответ 6
Ваш код должен работать отлично, я использую его так же. Только убедитесь, что если событие щелчка вызывается из всплывающего экрана, такого как загрузочный мод или что-то еще, созданный элемент должен находиться внутри этого модального режима, иначе он не будет копироваться. Вы всегда можете указать идентификатор элемента в этом модальном режиме (в качестве второго параметра) и получить его с помощью 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);
}
Ответ 7
Я использовал очень похожий подход, как некоторые из вышеперечисленных, но, по-моему, он стал немного более конкретным. Здесь родительский компонент передаст 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>
);
};
Ответ 8
Для тех людей, которые пытаются выбрать из 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)}
/>
);
}
Ответ 9
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>
)
}
}
Ответ 10
вот мой код:
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