ReaktJS'de metin panoya nasıl kopyalanır?


147

ReactJS kullanıyorum ve bir kullanıcı bir bağlantıyı tıklattığında panoya bazı metin kopyalamak istiyorum.

Chrome 52 kullanıyorum ve başka tarayıcıları desteklememe gerek yok.

Neden bu kod veri panoya kopyalanmıyor neden göremiyorum. (kod pasajının kaynağı bir Reddit postasından kaynaklanır).

Bunu yanlış mı yapıyorum? Herkes reaktjs kullanarak panoya kopya uygulamak için "doğru" bir yol olduğunu önerebilir?

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
Clipboardjs.com veya github.com/zeroclipboard/zeroclipboard gibi 3. taraf çözümlerini kullanmayı denediniz mi?
EugZol

11
@EugZol Kodun oldukça küçük olduğunu varsayarak, başka bir bağımlılık eklemek yerine kod yazmayı tercih ederim.
Duke Dougal

Bu yanıtları kontrol edin stackoverflow.com/questions/400212/…
elmeister

@elmeister soru reatjs'a özgü
Duke Dougal

Yanıtlar:


180

Şahsen bunun için bir kütüphane ihtiyacını görmüyorum. Http://caniuse.com/#feat=clipboard'a bakıldığında şu anda oldukça yaygın bir şekilde desteklenmektedir, ancak yine de işlevselliğin mevcut istemcide var olup olmadığını kontrol etmek gibi bir şey yapabilirsiniz ve yoksa kopyala düğmesini gizleyin.

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;

Güncelleme: React 16.7.0-alpha.0'daki React Hooks kullanılarak yeniden yazıldı

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

26
Bu en iyi cevap. Eski tarayıcı desteğine ihtiyaç duymadıkça geliştiricileri her küçük şey için paketleri kullanmaya teşvik etmemeliyiz.
tugce

3
Sadece kayıt için: bununla ilgili tek sorun, sayfadaki bazı metin öğelerinde bulunmayan metni kopyalamaya çalışıyorsanız, bir dizi DOM öğesini hacklemeniz, metni ayarlamanız, kopyalamanız, ve temizleyin. Bu çok küçük bir şey için bir sürü kod. Normalde geliştiricilerin kütüphaneleri sürekli yüklemeye teşvik edilmemesi gerektiğine katılıyorum.
Christopher Ronning

3
Bu özel sorun için, metin zaten sayfadaki bir öğede. Sayfada, kopyalamak istediğiniz öğede olmayan görünür metinlerin bulunduğu durumlarda ne olur? Bu, bir çözüm sunmaktan mutluluk duyacağım tamamen farklı bir konudur. Tepki ile hiçbir şeyi kesmek zorunda kalmazsınız, render fonksiyonunuzda metni de içeren gizli bir öğe sağlarsınız. Geçici öğeler oluşturmaya gerek yok.
Nate

2
Bu daktilo hatası alıyorum:Property 'select' does not exist on type 'never'
Alex C

3
TypeError alıyorum: textAreaRef.current.select bir işlev değil
pseudozach

120

Panoya programlı olarak veri yazmak istiyorsanız, bu basit satır içi onClick işlevini bir düğme üzerinde kullanın.

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

3
navigator.clipboard tüm tarayıcıları desteklemez
Premjeet

8
2018'de büyük tarayıcılar için iyi bir destek olduğu görülüyor caniuse.com/#search=clipboard
gasolin


2
metnimin kopyalanacağı yerdeki asıl sayfamın aslında sayfada olmadığı en iyi sonucu verir. Teşekkürler
NSjonas

1
Kısmi destek çok iyidir, bu nedenle çoğu kullanım durumunda tamamen desteklenir. Ve belirtildiği gibi, bu en iyi programatik çözümdür.
Dror Bar

40

Kesinlikle yukarıdaki @Shubham gibi bir paket kullanmayı düşünmelisiniz, ancak açıkladığınız şeye dayanarak bir çalışma kod kalemi oluşturdum: http://codepen.io/dtschust/pen/WGwdVN?editors=1111 . Chrome'da tarayıcımda çalışıyor, belki de orada kaçırdığınız bir şey olup olmadığını veya uygulamanızda bunun çalışmasını engelleyen bazı genişletilmiş karmaşıklık olup olmadığını görebilirsiniz.

// 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
Bir paket neden çözümünüzden daha iyi?
Duke Dougal

6
Potansiyel olarak daha iyi çapraz tarayıcı desteği ve hata düzeltilmesi gerektiğinde pakette daha fazla göz
Drew Schuster

tıkır tıkır çalışıyor. Evet. Çapraz tarayıcı desteğini de merak ediyorum.
Karl Pokus

appendChild kullandığınızdan bu yana ne kadar çabuk kaldırırsanız çıkartın, bu ekranda titremeye neden olur mu?
robinnnnn

1
Bu iyi, ancak Android'de Chrome (72.0) veya Android'de FF (63.0) üzerinde çalışmıyor.
colin

35

En basit yol react-copy-to-clipboard npm paketini .

Aşağıdaki komutla kurabilirsiniz

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

Aşağıdaki şekilde kullanın.

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şağıdaki linkte ayrıntılı bir açıklama verilmiştir.

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

İşte çalışan bir keman .


Tersine çevirmem gerekirse herhangi bir çözüm var mı? yani Yazar, bir e-postadaki tepkiyi reatjs uygulamasındaki metin alanına kopyalar. Html etiketleri korumak gerekmez, ancak, sadece satır sonlarını korumak gerekir.
TechTurtle

Muhtemelen onpasteetkinliği takmanız gerekiyor
Koen

Bir html tablosunun içeriğini panoya kopyalamak istersem bu paketi nasıl kullanabilirim? Straham Khatri
Jane Fred

19

Neden böyle bir düğmenin içine girebildiğinizde npm paketine ihtiyacınız var?

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

Umarım bu yardımcı olur @jerryurenaa


16

Neden sadece event clipboardData toplama yöntemini kullanmıyorsunuz e.clipboardData.setData(type, content)?

Bence pano içinde ikramiye elde etmek için en streightforward yöntemidir, bunu kontrol edin (yerel kopyalama eylemi sırasında verileri değiştirmek için kullandım):

...

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

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

Bu yolu takip ettim: https://developer.mozilla.org/en-US/docs/Web/Events/copy

Şerefe!

EDIT: Test amacıyla kod ekledim: https://codepen.io/dprzygodzki/pen/ZaJMKb


3
@KarlPokus Soru soran kişi yalnızca Chrome çözümü arıyor
TechTurtle

1
Chrome Sürüm 62.0.3202.94'te test edilmiştir. Çalışıyor. codepen.io/dprzygodzki/pen/ZaJMKb
Damian Przygodzki

1
@OliverDixon React olayının varsayılan nesnesidir. reaktjs.org/docs/events.html
Damian Przygodzki

1
@DamianPrzygodzki Böyle gizli öğelerden nefret ediyorum, geliştiricileri karıştırmanın harika bir yolu.
Oliver Dixon

1
@OliverDixon seni hissediyorum, ama bazen olaylara, özellikle olaylarda uygulanan bazı varsayılan veri olduğunu alışmak iyi olduğunu düşünüyorum.
Damian Przygodzki

8

Kodunuz mükemmel çalışmalı, ben de aynı şekilde kullanıyorum. Yalnızca click olayının, bir önyükleme yöntemi veya benzeri bir açılır ekrandan tetiklenmesi durumunda, oluşturulan öğenin bu modda olması gerektiğinden emin olun, aksi takdirde kopyalanmaz. Her zaman o mod içindeki bir öğenin kimliğini (ikinci parametre olarak) verebilir ve getElementById ile alabilir, ardından yeni oluşturulan öğeyi belge yerine bu öğeye ekleyebilirsiniz. Bunun gibi bir şey:

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

8

Yukarıdakilerin bazıları ile çok benzer bir yaklaşım izledim, ama bunu biraz daha somut hale getirdim. Burada, bir üst bileşen URL'yi (veya istediğiniz metni) prop olarak geçirir.

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

Bunun yerine Textarea yerine paragraf etiketi almak istedim
Ehsan Ahmadi

Teşekkürler!
Metin alanında

3

Metin alanı yerine DIV'den seçim yapmaya çalışanlar için işte kod. Kod açıklayıcıdır, ancak daha fazla bilgi istiyorsanız buraya yorum yapın:

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

3

Geçerli URL'yi panonuza kopyalamak istiyorsanız, başka bir kullanım örneği:

Bir yöntem tanımlama

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

Bu yöntemi çağırın

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

3

Reaksiyon kancalı en iyi çözüm, bunun için harici kütüphanelere gerek yok

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 belgeleri hakkında daha fazla belge için buraya bakın navigotor.clipboard çok sayıda tarayıcı tarafından desteklenmektedir.


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

1

Metin alanı yerine DIV arasından seçim yapmak istiyorsanız, kod İşte. "Kod" kopyalanması gereken değerdir

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

1
SO'nun en iyi uygulaması kodunuzu bir açıklama ile gerçekleştirmektir. Lütfen yap.
MartenCatcher

0

İşte benim kod:

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

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>

7
Lütfen kod göndermek yerine bu kodun sorunu nasıl çözdüğüne ilişkin bir açıklama ekleyin.
Alexander van Oostenrijk

0

Bunu yapmanın en iyi yolunu buldum. en hızlı yolu kastediyorum: w3school

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

Bir reaksiyon fonksiyonel bileşeninin içinde. HandleCopy adlı bir işlev oluşturun:

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 kullanmıyorsanız, w3schools'un bunu dahil araç ipucu ile yapmanın harika bir yolu vardır: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_copy_clipboard2

React kullanıyorsanız, havalı bir düşünün: Mesajı uyarmak için bir Toastify kullanın. https://github.com/fkhadra/react-toastify Bu, kullanımı çok kolay bir lib. Kurulumdan sonra bu satırı değiştirebilirsiniz:

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

Gibi bir şey için:

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

Kullanmak istiyorsanız tostify'ı kurmayı unutmayın. ToastContainer'ı içe aktarın ve ayrıca toss css:

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

ve tost kabını geri dönüş içine ekleyin.

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

Yanıtınız yalnızca başka bir kaynağa yapılan referansı içeriyor, ancak belirli bir yanıt yok. W3schools doğru çözüm olarak bağlanıyorsa, lütfen buraya yazın.
f.khantsis
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.