Wie kopiere ich in reactJS Text in die Zwischenablage?

145

Ich verwende ReactJS und wenn ein Benutzer auf einen Link klickt, möchte ich Text in die Zwischenablage kopieren.

Ich verwende Chrome 52 und muss keine anderen Browser unterstützen.

Ich kann nicht verstehen, warum dieser Code nicht dazu führt, dass die Daten in die Zwischenablage kopiert werden. (Der Ursprung des Code-Snippets stammt aus einem Reddit-Beitrag).

Mache ich das falsch Kann jemand vorschlagen, dass es eine "richtige" Möglichkeit gibt, das Kopieren in die Zwischenablage mithilfe von reactjs zu implementieren?

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()
}
Herzog Dougal
quelle
1
Haben Sie versucht, Lösungen von Drittanbietern wie clipboardjs.com oder github.com/zeroclipboard/zeroclipboard zu verwenden ?
EugZol
10
@EugZol Ich schreibe wirklich lieber Code als eine weitere Abhängigkeit hinzuzufügen, vorausgesetzt, der Code ist ziemlich klein.
Duke Dougal
Überprüfen Sie diese Antworten stackoverflow.com/questions/400212/…
elmeister
@elmeister die Frage ist spezifisch für Reaktionen
Duke Dougal

Antworten:

179

Ich persönlich sehe dafür keine Notwendigkeit für eine Bibliothek. Unter http://caniuse.com/#feat=clipboard wird es derzeit weitgehend unterstützt. Sie können jedoch weiterhin prüfen, ob die Funktionalität im aktuellen Client vorhanden ist, und die Schaltfläche zum Kopieren einfach ausblenden, wenn dies nicht der Fall ist.

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: Mit React Hooks in React 16.7.0-alpha.0 neu geschrieben

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>
  );
}
Nate
quelle
26
Dies ist die beste Antwort. Wir sollten Entwickler nicht dazu ermutigen, Pakete für jede Kleinigkeit zu verwenden, es sei denn, sie benötigen alte Browserunterstützung.
Tugce
2
Nur zur Veranschaulichung: Das einzige Problem dabei ist, dass Sie, wenn Sie versuchen, Text zu kopieren, der noch nicht in einem Textelement auf der Seite enthalten ist, eine Reihe von DOM-Elementen hacken, den Text festlegen, kopieren müssen. und aufräumen. Das ist viel Code für etwas sehr Kleines. Normalerweise würde ich zustimmen, dass Entwickler nicht dazu ermutigt werden sollten, ständig Bibliotheken zu installieren.
Christopher Ronning
3
Für dieses spezielle Problem befindet sich der Text bereits in einem Element auf der Seite. In welchem ​​Fall befindet sich auf der Seite, die Sie kopieren möchten, sichtbarer Text, der sich nicht in einem Element befindet? Das ist ein ganz anderes Problem, für das ich gerne eine Lösung zeigen würde. Sie müssten nichts mit reagieren hacken, sondern nur ein verstecktes Element in Ihrer Renderfunktion bereitstellen, das auch den Text enthält. Keine Notwendigkeit, Elemente ad hoc zu erstellen.
Nate
2
Ich erhalte diesen Typoskriptfehler:Property 'select' does not exist on type 'never'
Alex C
2
Ich bekomme TypeError: textAreaRef.current.select ist keine Funktion
Pseudozach
118

Verwenden Sie diese einfache Inline-Funktion onClick für eine Schaltfläche, wenn Sie programmgesteuert Daten in die Zwischenablage schreiben möchten.

onClick={() => {navigator.clipboard.writeText(this.state.textToCopy)}}
Gary Vernon Grubb
quelle
3
navigator.clipboard unterstützt nicht alle Browser
Premjeet
8
scheint, dass es für große Browser im Jahr 2018 gut unterstützt wurde caniuse.com/#search=clipboard
Benzin
2
Basierend auf dem Link, den Sie bereitgestellt haben, sieht es so aus, als ob es nur auf Safari vollständig unterstützt wird ...
Nibb
2
funktioniert am besten für meinen Fall, dass der zu kopierende Text nicht tatsächlich auf der Seite ist. Danke
NSjonas
1
Die teilweise Unterstützung ist sehr gut, daher wird sie für die meisten Anwendungsfälle vollständig unterstützt. Und wie bereits erwähnt, ist dies die beste programmatische Lösung.
Dror Bar
40

Sie sollten auf jeden Fall in Betracht ziehen, ein Paket wie @ Shubham zu verwenden, aber ich habe einen funktionierenden Codepen erstellt, der auf dem basiert, was Sie beschrieben haben: http://codepen.io/dtschust/pen/WGwdVN?editors=1111 . Es funktioniert in meinem Browser in Chrome. Vielleicht können Sie sehen, ob ich dort etwas getan habe, das Sie verpasst haben, oder ob Ihre Anwendung eine erweiterte Komplexität aufweist, die dies verhindert.

// 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'))
Drew Schuster
quelle
3
Warum ist ein Paket besser als Ihre Lösung?
Duke Dougal
6
Potenziell bessere browserübergreifende Unterstützung und mehr Augen für das Paket, falls ein Fehler behoben werden muss
Drew Schuster
klappt wunderbar. Ja. Ich frage mich auch über die Cross-Browser-Unterstützung.
Karl Pokus
Würde dies ein Flackern auf dem Bildschirm verursachen, wenn Sie appendChild verwenden, unabhängig davon, wie schnell Sie es anschließend entfernen?
Robinnnnn
1
Dies ist gut, funktioniert aber weder unter Chrome (72.0) unter Android noch unter FF (63.0) unter Android.
Colin
34

Der einfachste Weg ist die Verwendung der react-copy-to-clipboard npm-Paket zu verwenden.

Sie können es mit dem folgenden Befehl installieren

npm install --save react react-copy-to-clipboard

Verwenden Sie es wie folgt.

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'));

Eine ausführliche Erklärung finden Sie unter folgendem Link

https://www.npmjs.com/package/react-copy-to-clipboard

Hier ist eine laufende Geige .

Shubham Khatri
quelle
Gibt es eine Lösung, wenn ich das Gegenteil tun muss? Das heißt, der Autor kopiert Text aus einer E-Mail in den Textbereich der Reactjs-Anwendung. Ich muss keine HTML-Tags beibehalten, aber ich muss nur Zeilenumbrüche beibehalten.
TechTurtle
Sie müssen wahrscheinlich das onpasteEreignis einstecken
Koen
Wie kann ich dieses Paket verwenden, wenn ich den Inhalt einer HTML-Tabelle in die Zwischenablage kopieren möchte? @ Shubham Khatri
Jane Fred
19

Warum verwenden Sie ein npm-Paket, wenn Sie alle innerhalb einer einzigen Schaltfläche wie dieser erhalten können?

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

Ich hoffe das hilft @jerryurenaa

jerryurenaa
quelle
16

Warum nicht nur die Erfassungsmethode event clipboardData verwenden? e.clipboardData.setData(type, content) ?

Meiner Meinung nach ist dies die einfachste Methode, um etw in die Zwischenablage zu verschieben. Überprüfen Sie dies (ich habe es verwendet, um Daten während der nativen Kopieraktion zu ändern):

...

handleCopy = (e) => {
    e.preventDefault();
    e.clipboardData.setData('text/plain', 'Hello, world!');
}

render = () =>
    <Component
        onCopy={this.handleCopy}
    />

Ich bin diesem Weg gefolgt: https://developer.mozilla.org/en-US/docs/Web/Events/copy

Prost!

BEARBEITEN: Zu Testzwecken habe ich Codepen hinzugefügt: https://codepen.io/dprzygodzki/pen/ZaJMKb

Damian Przygodzki
quelle
3
@ KarlPokus Der Fragesteller sucht nur nach Chrome-Lösung
TechTurtle
1
Getestet auf Chrome Version 62.0.3202.94. Es funktioniert. codepen.io/dprzygodzki/pen/ZaJMKb
Damian Przygodzki
1
@OliverDixon ist das Standardobjekt des React-Ereignisses. reactjs.org/docs/events.html
Damian Przygodzki
1
@DamianPrzygodzki Ich hasse solche versteckten Elemente, eine großartige Möglichkeit, Entwickler zu verwirren.
Oliver Dixon
1
@OliverDixon Ich fühle dich, aber ich denke, es ist gut, sich daran zu gewöhnen, dass manchmal einige Standarddaten auf die Methode angewendet werden, insbesondere bei Ereignissen.
Damian Przygodzki
8

Ihr Code sollte perfekt funktionieren, ich benutze ihn genauso. Stellen Sie nur sicher, dass sich das erstellte Element innerhalb dieses Modals befindet, wenn das Klickereignis in einem Popup-Bildschirm wie einem Bootstrap-Modal oder Ähnlichem ausgelöst wird. Andernfalls wird es nicht kopiert. Sie können jederzeit die ID eines Elements in diesem Modal (als zweiten Parameter) angeben und mit getElementById abrufen und dann das neu erstellte Element anstelle des Dokuments an dieses Element anhängen. Etwas wie das:

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);
}
Kupi
quelle
8

Ich habe einen sehr ähnlichen Ansatz gewählt wie einige der oben genannten, aber ich denke, er wurde etwas konkreter. Hier übergibt eine übergeordnete Komponente die URL (oder einen beliebigen Text) als Requisite.

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>
  );
};
tjgragg
quelle
Dies war nützlich, weil ich stattdessen ein Absatz-Tag für Textarea
Ehsan Ahmadi
Vielen Dank! Das einzige Problem ist das Ausblenden des Textfelds
es wird
3

Für diejenigen Personen, die versuchen, anstelle des Textfelds aus dem DIV auszuwählen, ist hier der Code. Der Code ist selbsterklärend, aber kommentieren Sie hier, wenn Sie weitere Informationen wünschen:

     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)}
                        />
                    );
            }
connect2Coder
quelle
3

Hier ist ein weiterer Anwendungsfall, wenn Sie die aktuelle URL in Ihre Zwischenablage kopieren möchten:

Definieren Sie eine Methode

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

Rufen Sie diese Methode auf

<button copyToClipboard={shareLink}>
   Click to copy current url to clipboard
</button>
jasonleonhard
quelle
2
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>
        )
    }
}
Yash Pokar
quelle
2

Beste Lösung mit React Hooks, dafür sind keine externen Bibliotheken erforderlich

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

Weitere Dokumentation zu navigator.clip board , navigator.clipboard Dokumentation finden Sie hier. navigotor.clipboard wird von einer Vielzahl von Browsern unterstützt

Jaman-Dedy
quelle
1

Wenn Sie anstelle des Textfelds aus dem DIV auswählen möchten, finden Sie hier den Code. Der "Code" ist der Wert, der kopiert werden muss

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
Haris George
quelle
1
Die beste Vorgehensweise für SO besteht darin, Ihren Code mit einer Erklärung zu versehen. Bitte tu es.
MartenCatcher
0

Hier ist mein 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
Alan
quelle
0
<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>
Bob
quelle
7
Bitte fügen Sie eine Erklärung hinzu, wie dieser Code das Problem löst, anstatt nur Code zu veröffentlichen.
Alexander van Oostenrijk
0

Den besten Weg gefunden, es zu tun. Ich meine den schnellsten Weg: w3school

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

Innerhalb einer Reaktionsfunktionskomponente. Erstellen Sie eine Funktion mit dem Namen 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="[email protected]"
                id="mail"
              />
              <button onClick={handleCopy}>Copy email</button>

</>

Wenn Sie React nicht verwenden, haben w3schools auch eine coole Möglichkeit, dies mit dem enthaltenen Tooltip zu tun: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_copy_clipboard2

Wenn Sie React verwenden, sollten Sie Folgendes tun: Verwenden Sie Toastify, um die Nachricht zu benachrichtigen. https://github.com/fkhadra/react-toastify Dies ist die Bibliothek, die sehr einfach zu bedienen ist. Nach der Installation können Sie möglicherweise diese Zeile ändern:

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

Für so etwas wie:

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

Wenn Sie es verwenden möchten, vergessen Sie nicht, toastify zu installieren. importiere ToastContainer und auch Toast CSS:

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

und fügen Sie den Toastbehälter im Rücklauf hinzu.

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="[email protected]"
                id="mail"
              />
              <button onClick={handleCopy}>Copy Email</button>
      </Container>
    </>
  )
}
Iago Barreto
quelle
Ihre Antwort enthält nur den Verweis auf eine andere Ressource, jedoch keine spezifische Antwort. Wenn der Link w3schools die richtige Lösung ist, geben Sie ihn bitte hier ein.
f.khantsis