Pytanie W reactJS, jak skopiować tekst do schowka?


Używam ReactJS i gdy użytkownik kliknie łącze, chcę skopiować jakiś tekst do schowka.

Używam Chrome 52 i nie muszę obsługiwać żadnych innych przeglądarek.

Nie widzę powodu, dla którego ten kod nie spowoduje skopiowania danych do schowka. (pochodzenie fragmentu kodu pochodzi z posta Reddit).

Czy robię to źle? Czy ktokolwiek może sugerować, że istnieje "poprawny" sposób zaimplementowania kopii do schowka za pomocą reaktji?

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

23
2017-09-14 23:52


pochodzenie


Czy próbowałeś używać rozwiązań innych firm, takich jak clipboardjs.com lub github.com/zeroclipboard/zeroclipboard? - EugZol
@EugZol Naprawdę wolę pisać kod zamiast dodawać kolejną zależność, zakładając, że kod jest dość mały. - Duke Dougal
Sprawdź te odpowiedzi stackoverflow.com/questions/400212/... - elmeister
@elmeister pytanie jest specyficzne dla reactjs - Duke Dougal


Odpowiedzi:


Najprostszym sposobem będzie użycie react-copy-to-clipboard pakiet npm.

Możesz zainstalować go za pomocą następującego polecenia

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

Użyj go w następujący sposób.

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

Szczegółowe wyjaśnienie znajduje się pod poniższym linkiem

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

Oto bieg skrzypce.


20
2017-09-15 06:51



Czy istnieje jakieś rozwiązanie, jeśli muszę zrobić odwrotność? tzn. autor skopiuje tekst z wiadomości e-mail do obszaru tekstowego w aplikacji reactjs. Nie muszę przechowywać znaczników html, ale muszę zachować tylko podziały wierszy. - TechTurtle
Prawdopodobnie musisz podłączyć onpaste zdarzenie - Koen


Powinieneś zdecydowanie rozważyć skorzystanie z powyższego pakietu, np. @Shubham, ale utworzyłem działający codepen na podstawie tego, co opisałeś: http://codepen.io/dtschust/pen/WGwdVN?editors=1111 . Działa w mojej przeglądarce w chrome, być może widzisz, czy jest coś, co tam zrobiłem, że przegapiłeś, lub jeśli w twojej aplikacji jest trochę rozbudowana złożoność, która uniemożliwia to działanie.

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

18
2017-09-15 06:55



Dlaczego pakiet jest lepszy od twojego rozwiązania? - Duke Dougal
Potencjalnie lepsza obsługa wielu przeglądarek i więcej uwagi na pakiecie w przypadku, gdy trzeba naprawić błąd - Drew Schuster
działa jak marzenie. Tak. Zastanawiam się również nad obsługą wielu przeglądarek. - Karl Pokus


Osobiście nie widzę potrzeby posiadania do tego biblioteki. Patrzeć na http://caniuse.com/#feat=clipboard jest dość powszechnie obsługiwany, jednak wciąż możesz zrobić takie rzeczy, jak sprawdzenie, czy funkcjonalność istnieje w bieżącym kliencie i po prostu ukryć przycisk kopiowania, jeśli nie.

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;

16
2018-03-16 21:15



świetne rozwiązanie :) - Pixelomo
To jest najlepsza odpowiedź. Nie powinniśmy zachęcać programistów do używania pakietów na każdą małą rzecz, chyba że potrzebują starej obsługi przeglądarki. - tugce
Dla przykładu: jedynym problemem jest to, że jeśli próbujesz skopiować tekst, który nie znajduje się jeszcze w jakimś elemencie tekstowym na stronie, musisz zhackować zestaw elementów DOM, ustawić tekst, skopiować go, i posprzątaj to. To dużo kodu na coś bardzo małego. Zwykle zgadzam się, że twórcy bibliotek nie powinni zachęcać twórców do ciągłego instalowania. - Christopher Ronning
W przypadku tego konkretnego problemu tekst znajduje się już w elemencie na stronie. Jaka jest sytuacja, w której na stronie znajduje się widoczny tekst, który chcesz skopiować, a który nie jest elementem? To zupełnie inny problem, który chętnie przedstawię. Nie musisz zhakować niczego, aby zareagować, wystarczy, że podasz ukryty element w funkcji renderowania, który również będzie zawierał tekst. Nie ma potrzeby tworzenia elementów ad hoc. - Nate


Dlaczego nie użyć metody zbierania zdarzeń clipboardData e.clipboardData.setData(type, content)?

Moim zdaniem jest to najbardziej optymalna metoda, aby osiągnąć popychanie w schowku, sprawdź to (użyłem tego do modyfikacji danych podczas działania kopiowania natywnego):

...

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

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

Podążyłem tą ścieżką: https://developer.mozilla.org/en-US/docs/Web/Events/copy

Twoje zdrowie!

EDYCJA: W celach testowych dodałem kodepen: https://codepen.io/dprzygodzki/pen/ZaJMKb


7
2018-03-28 08:16



brak wsparcia dla clipboardData  w IE - Karl Pokus
@KarlPokus Pytający szuka tylko rozwiązania Chrome - TechTurtle
nie działa w Chrome - ian
Przetestowano w wersji Chrome 62.0.3202.94. To działa. codepen.io/dprzygodzki/pen/ZaJMKb - Damian Przygodzki
@ian, a także, aby udostępnić powtarzalny kod problemu. - Damian Przygodzki


Twój kod powinien działać idealnie, używam go w ten sam sposób. Upewnij się tylko, że jeśli zdarzenie kliknięcia zostanie wywołane z wyskakującego ekranu, takiego jak modulator bootstrap lub coś takiego, utworzony element musi znajdować się w tym modalu, w przeciwnym razie nie będzie kopiowany. Zawsze możesz podać id elementu w tym modalu (jako drugi parametr) i pobrać go za pomocą getElementById, a następnie dołączyć nowo utworzony element do tego, zamiast do dokumentu. Coś takiego:

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

3
2018-02-21 14:47





Dla tych osób, które próbują wybrać z DIV zamiast pola tekstowego, tutaj jest kod. Kod jest oczywisty, ale komentarz tutaj, jeśli chcesz uzyskać więcej informacji:

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

0
2018-04-16 17:26