Проблема

Обычно копирование текста происходит так (взято отсюда):

  1. Создайте элемент <textarea>, который будет добавлен к документу. Установите его value на строку, которую мы хотим скопировать в буфер обмена.
  2. Добавьте указанный элемент <textarea> к текущему HTML-документу.
  3. Используйте HTMLInputElement.select() для выбора содержимого элемента <textarea>.
  4. Используйте document.execCommand('copy'), чтобы скопировать содержимое <textarea> в буфер обмена.
  5. Удалите элемент <textarea> из документа.

Код выглядит следующим образом:

function copyToClipboard(text) {
  const el = document.createElement('textarea');
  el.value = text;
  document.body.appendChild(el);
  el.select();
  document.execCommand('copy');
  document.body.removeChild(el);
};

При таком подходе есть две проблемы:

  1. Возможно некоторое мигание из-за временного элемента <textarea>.
  2. Он отменит выбор всего, что выбирает пользователь.

Мы можем обойти и то, и другое, но функция станет намного длиннее.

Решение

Когда пользователь инициирует действие копирования, пользовательский агент запускает копирование имени события буфера обмена.

— Спецификация W3C

  1. Используйте addEventListener, чтобы прикрепить наш пользовательский обработчик событий, который заменит текущие данные нашим текстом.
  2. Используйте document.execCommand('copy') для запуска действия копирования.
  3. Используйте removeEventListener, чтобы удалить наш обработчик событий.
function copyToClipboard(text) {
  const listener = function(ev) {
    ev.preventDefault();
    ev.clipboardData.setData('text/plain', text);
  };
  document.addEventListener('copy', listener);
  document.execCommand('copy');
  document.removeEventListener('copy', listener);
}

Бонус

Вы даже можете скопировать форматированный текст!

function copyRichText(text) {
  const listener = function(ev) {
    ev.preventDefault();
    ev.clipboardData.setData('text/html', text);
    ev.clipboardData.setData('text/plain', text);
  };
  document.addEventListener('copy', listener);
  document.execCommand('copy');
  document.removeEventListener('copy', listener);
}
copyRichText('<i>Markup</i> <b>text</b>. Paste me into a rich text editor.');

Совместимость с браузером

Согласно веб-документам MDN, это должно работать во всех основных браузерах, кроме Internet Explorer.

Первоначально опубликовано на https://komsciguy.com 23 мая 2020 г.