Вопрос: Как скопировать в буфер обмена в JavaScript?


Каков наилучший способ скопировать текст в буфер обмена? (Мульти-браузер)

Я пытался:

function copyToClipboard(text) {
    if (window.clipboardData) { // Internet Explorer
        window.clipboardData.setData("Text", text);
    } else {  
        unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  
        const clipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);  
        clipboardHelper.copyString(text);
    }
}

но в Internet Explorer он дает синтаксическую ошибку. В Firefox говорится: unsafeWindow is not defined,

Хороший трюк без вспышки: Как Trello получает доступ к буферу пользователя?


2619


источник


Ответы:


обзор

Для копирования в буфер обмена есть 3 основных API-интерфейса браузера:

  1. API асинхронного буфера обмена [navigator.clipboard.writeText]
    • Текстовая часть, доступная в Chrome 66 (март 2018 года)
    • Доступ является асинхронным и использует JavaScript-обещания , могут быть записаны так, чтобы пользовательские запросы безопасности (если они отображаются) не прерывали JavaScript на странице.
    • Текст можно скопировать в буфер обмена непосредственно из переменной.
    • Поддерживается только на страницах, обслуживаемых HTTPS.
    • В Chrome 66 страниц на активных вкладках можно записать в буфер обмена без подсказки разрешений.
  2. document.execCommand('copy')
    • Большинство браузеров поддерживают это по состоянию на апрель 2015 года (см. Раздел Поддержка браузера ниже).
    • Доступ является синхронным, т. Е. Останавливает JavaScript на странице до завершения, включая отображение и взаимодействие пользователя с любыми запросами безопасности.
    • Текст считывается из DOM и помещается в буфер обмена.
    • Во время тестирования ~ апрель 2015 года только Internet Explorer был отмечен как отображение приглашений разрешений при записи в буфер обмена.
  3. Переопределение события копирования
    • См. Документацию API буфера обмена Переопределение события копирования ,
    • Позволяет изменять то, что отображается в буфере обмена из любого события копирования, может включать другие форматы данных, отличные от обычного текста.
    • Здесь не рассматривается, так как он прямо не отвечает на вопрос.

Общие примечания к разработке

Не ожидайте, что команды, связанные с буфером обмена, будут работать, пока вы тестируете код в консоли. Как правило, страница должна быть активной (API-интерфейс Async Clipboard) или требует взаимодействия с пользователем (например, щелчка пользователя), чтобы разрешить ( document.execCommand('copy')) для доступа к буферу см. ниже для более подробной информации.

Async + Fallback

Из-за уровня поддержки браузера для нового API-интерфейса Async Clipboard вы, скорее всего, захотите вернуться к document.execCommand('copy')чтобы получить хорошее покрытие браузера.

Вот простой пример:

function fallbackCopyTextToClipboard(text) {
  var textArea = document.createElement("textarea");
  textArea.value = text;
  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Fallback: Copying text command was ' + msg);
  } catch (err) {
    console.error('Fallback: Oops, unable to copy', err);
  }

  document.body.removeChild(textArea);
}
function copyTextToClipboard(text) {
  if (!navigator.clipboard) {
    fallbackCopyTextToClipboard(text);
    return;
  }
  navigator.clipboard.writeText(text).then(function() {
    console.log('Async: Copying to clipboard was successful!');
  }, function(err) {
    console.error('Async: Could not copy text: ', err);
  });
}

var copyBobBtn = document.querySelector('.js-copy-bob-btn'),
  copyJaneBtn = document.querySelector('.js-copy-jane-btn');

copyBobBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Bob');
});


copyJaneBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Jane');
});
<div style="display:inline-block; vertical-align:top;">
  <button class="js-copy-bob-btn">Set clipboard to BOB</button><br /><br />
  <button class="js-copy-jane-btn">Set clipboard to JANE</button>
</div>
<div style="display:inline-block;">
  <textarea class="js-test-textarea" cols="35" rows="4">Try pasting into here to see what you have on your clipboard:
  
  </textarea>
</div>

Обратите внимание, что этот фрагмент не работает в встроенном предварительном просмотре StackOverflow, вы можете попробовать его здесь: https://codepen.io/DeanMarkTaylor/pen/RMRaJX?editors=1011

API асинхронного буфера обмена

Обратите внимание, что есть возможность «запросить разрешение» и проверить доступ к буферу через API разрешений в Chrome 66.

var text = "Example text to appear on clipboard";
navigator.clipboard.writeText(text).then(function() {
  console.log('Async: Copying to clipboard was successful!');
}, function(err) {
  console.error('Async: Could not copy text: ', err);
});

document.execCommand ( 'копия')

В остальной части этого сообщения перечисляются нюансы и детали document.execCommand('copy')API.

Поддержка браузера

JavaScript document.execCommand('copy')поддержка выросла, см. ссылки ниже для обновлений браузера:

Простой пример

var copyTextareaBtn = document.querySelector('.js-textareacopybtn');

copyTextareaBtn.addEventListener('click', function(event) {
  var copyTextarea = document.querySelector('.js-copytextarea');
  copyTextarea.focus();
  copyTextarea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copying text command was ' + msg);
  } catch (err) {
    console.log('Oops, unable to copy');
  }
});
<p>
  <button class="js-textareacopybtn" style="vertical-align:top;">Copy Textarea</button>
  <textarea class="js-copytextarea">Hello I'm some text</textarea>
</p>

Сложный пример: копирование в буфер обмена без отображения ввода

Вышеприведенный простой пример отлично работает, если есть textareaили inputэлемент видимый на экране.

В некоторых случаях вы можете скопировать текст в буфер обмена, не отображая input/ textareaэлемент. Это один из примеров способа обойти это (в основном вставить элемент, скопировать в буфер обмена, удалить элемент):

Протестировано с Google Chrome 44, Firefox 42.0a1 и IE 11.0.8600.17814.

function copyTextToClipboard(text) {
  var textArea = document.createElement("textarea");

  //
  // *** This styling is an extra step which is likely not required. ***
  //
  // Why is it here? To ensure:
  // 1. the element is able to have focus and selection.
  // 2. if element was to flash render it has minimal visual impact.
  // 3. less flakyness with selection and copying which **might** occur if
  //    the textarea element is not visible.
  //
  // The likelihood is the element won't even render, not even a flash,
  // so some of these are just precautions. However in IE the element
  // is visible whilst the popup box asking the user for permission for
  // the web page to copy to the clipboard.
  //

  // Place in top-left corner of screen regardless of scroll position.
  textArea.style.position = 'fixed';
  textArea.style.top = 0;
  textArea.style.left = 0;

  // Ensure it has a small width and height. Setting to 1px / 1em
  // doesn't work as this gives a negative w/h on some browsers.
  textArea.style.width = '2em';
  textArea.style.height = '2em';

  // We don't need padding, reducing the size if it does flash render.
  textArea.style.padding = 0;

  // Clean up any borders.
  textArea.style.border = 'none';
  textArea.style.outline = 'none';
  textArea.style.boxShadow = 'none';

  // Avoid flash of white box if rendered for any reason.
  textArea.style.background = 'transparent';


  textArea.value = text;

  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();

  try {
    var successful = document.execCommand('copy');
    var msg = successful ? 'successful' : 'unsuccessful';
    console.log('Copying text command was ' + msg);
  } catch (err) {
    console.log('Oops, unable to copy');
  }

  document.body.removeChild(textArea);
}


var copyBobBtn = document.querySelector('.js-copy-bob-btn'),
  copyJaneBtn = document.querySelector('.js-copy-jane-btn');

copyBobBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Bob');
});


copyJaneBtn.addEventListener('click', function(event) {
  copyTextToClipboard('Jane');
});
<div style="display:inline-block; vertical-align:top;">
  <button class="js-copy-bob-btn">Set clipboard to BOB</button><br /><br />
  <button class="js-copy-jane-btn">Set clipboard to JANE</button>
</div>
<div style="display:inline-block;">
  <textarea class="js-test-textarea" cols="35" rows="4">Try pasting into here to see what you have on your clipboard:
  
  </textarea>
</div>

Дополнительные замечания

Работает только в том случае, если пользователь предпринимает действия

Все document.execCommand('copy')вызовы должны выполняться как прямой результат действия пользователя, например. щелкните обработчик события. Это мера, чтобы предотвратить беспорядок с клиентом буфера обмена, когда они этого не ожидают.

См. Разработчики Google публикуют здесь для получения дополнительной информации.

API буфера обмена

Обратите внимание, что полный проект спецификации API буфера обмена можно найти здесь: https://w3c.github.io/clipboard-apis/

Поддерживается ли это?

  • document.queryCommandSupported('copy')должен вернуться trueесли команда «поддерживается браузером».
  • а также document.queryCommandEnabled('copy')вернуть trueесли document.execCommand('copy')будет успешным, если будет вызвано сейчас. Проверка, чтобы команда вызывалась из потока, инициированного пользователем, и выполнялись другие требования.

Однако, как пример проблем совместимости браузера, Google Chrome с ~ апреля до ~ trueиз document.queryCommandSupported('copy')если команда была вызвана из инициированного пользователем потока.

Подробнее см. Ниже.

Сведения о совместимости браузера

В то время как простой вызов document.execCommand('copy')завернутый в try/ catchблок, вызванный в результате щелчка пользователя, вы получите наибольшее использование совместимости. Ниже приведены некоторые оговорки:

Любой звонок document.execCommand, document.queryCommandSupportedили document.queryCommandEnabledдолжны быть завернуты в try/ catchблок.

Различные версии браузера и версии браузера вызывают разные типы исключений при вызове вместо возврата false,

Различные реализации браузеров все еще находятся в движении, и API буфера обмена все еще в проекте, поэтому не забудьте выполнить свое тестирование.


1547



Автоматическое копирование в буфер обмена может быть опасным, поэтому большинство браузеров (кроме IE) делают это очень сложным. Лично я использую следующий простой трюк:

function copyToClipboard(text) {
  window.prompt("Copy to clipboard: Ctrl+C, Enter", text);
}

Пользователю предоставляется окно приглашения, в котором уже выбран текст, который нужно скопировать. Теперь достаточно нажать Ctrl + С а также Войти (закрыть окно) - и вуаля!

Теперь операция копирования буфера обмена SAFE, потому что пользователь делает это вручную (но довольно просто). Конечно, работает во всех браузерах.

<button id="demo" onclick="copyToClipboard(document.getElementById('demo').innerHTML)">This is what I want to copy</button>

<script>
  function copyToClipboard(text) {
    window.prompt("Copy to clipboard: Ctrl+C, Enter", text);
  }
</script>


1191



Следующий подход работает в Chrome, Firefox, Internet Explorer и Edge, а также в последних версиях Safari (поддержка копирования была добавлена ​​в версии 10, выпущенной в октябре 2016 года).

  • Создайте текстовое поле и установите его содержимое в текст, который вы хотите скопировать в буфер обмена.
  • Добавьте текстовое поле в DOM.
  • Выберите текст в текстовом поле.
  • Вызовите document.execCommand («копировать»)
  • Удалите текстовое поле из dom.

Примечание. Вы не увидите текстовое поле, так как оно будет добавлено и удалено в рамках одного и того же синхронного вызова кода Javascript.

Некоторые вещи, о которых следует помнить, если вы сами это реализуете:

  • По соображениям безопасности это можно вызвать только из обработчика событий, такого как щелчок (точно так же, как при открытии окон).
  • При первом обновлении буфера обмена IE отобразит диалоговое окно с разрешением.
  • IE и Edge будут прокручиваться, когда текстовая область будет сфокусирована.
  • execCommand () может вызывать в некоторых случаях.
  • Новые строки и вкладки могут быть проглочены, если вы не используете текстовое поле. (Большинство статей, похоже, рекомендуют использовать div)
  • Текстовое поле будет отображаться, пока отображается диалоговое окно IE, вам нужно либо скрыть его, либо использовать специфичный для IE файл clipboardData api.
  • В IE системные администраторы могут отключить API буфера обмена.

Приведенная ниже функция должна обрабатывать все следующие проблемы как можно чище. Пожалуйста, оставьте комментарий, если вы обнаружите какие-либо проблемы или у вас есть предложения по его улучшению.

// Copies a string to the clipboard. Must be called from within an 
// event handler such as click. May return false if it failed, but
// this is not always possible. Browser support for Chrome 43+, 
// Firefox 42+, Safari 10+, Edge and IE 10+.
// IE: The clipboard feature may be disabled by an administrator. By
// default a prompt is shown the first time the clipboard is 
// used (per session).
function copyToClipboard(text) {
    if (window.clipboardData && window.clipboardData.setData) {
        // IE specific code path to prevent textarea being shown while dialog is visible.
        return clipboardData.setData("Text", text); 

    } else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
        var textarea = document.createElement("textarea");
        textarea.textContent = text;
        textarea.style.position = "fixed";  // Prevent scrolling to bottom of page in MS Edge.
        document.body.appendChild(textarea);
        textarea.select();
        try {
            return document.execCommand("copy");  // Security exception may be thrown by some browsers.
        } catch (ex) {
            console.warn("Copy to clipboard failed.", ex);
            return false;
        } finally {
            document.body.removeChild(textarea);
        }
    }
}

https://jsfiddle.net/fx6a6n6x/


189



Если вы хотите действительно простое решение (требуется менее 5 минут для интеграции) и хорошо выглядит прямо из коробки, то Clippy - отличная альтернатива некоторым более сложным решениям.

Clippy

Это было написано одним из основателей Гитуба. Пример Flash вставлять код ниже:

<object 
   classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
   width="110"
   height="14"
   id="clippy">
  <param name="movie" value="/flash/clippy.swf"/>
  <param name="allowScriptAccess" value="always"/>
  <param name="quality" value="high"/>
  <param name="scale" value="noscale"/>
  <param NAME="FlashVars" value="text=#{text}"/>
  <param name="bgcolor" value="#{bgcolor}"/>
  <embed 
     src="/flash/clippy.swf"
     width="110"
     height="14"
     name="clippy"
     quality="high"
     allowScriptAccess="always"
     type="application/x-shockwave-flash"
     pluginspage="http://www.macromedia.com/go/getflashplayer"
     FlashVars="text=#{text}"
     bgcolor="#{bgcolor}"/>
</object>

Не забудьте заменить #{text}с текстом, который вам нужно скопировать, и #{bgcolor}с цветом.


93



Чтение и изменение буфера обмена с веб-страницы повышает безопасность и конфиденциальность. Однако в Internet Explorer это возможно. я нашел это пример фрагмента :

    <script type="text/javascript">
        function select_all(obj) {
            var text_val=eval(obj);
            text_val.focus();
            text_val.select();
            r = text_val.createTextRange();
            if (!r.execCommand) return; // feature detection
            r.execCommand('copy');
        }
    </script>
    <input value="http://www.sajithmr.com"
     onclick="select_all(this)" name="url" type="text" />


76



Недавно я написал техническое сообщение в блоге по этой самой проблеме (я работаю в Lucidchart, и недавно мы провели капитальный ремонт в нашем буфере обмена).

Копирование обычного текста в буфер обмена относительно просто, если вы хотите сделать это во время события системной копии (пользовательские нажатия Ctrl С или использует меню браузера).

var isIe = (navigator.userAgent.toLowerCase().indexOf("msie") != -1 
           || navigator.userAgent.toLowerCase().indexOf("trident") != -1);

document.addEventListener('copy', function(e) {
    var textToPutOnClipboard = "This is some text";
    if (isIe) {
        window.clipboardData.setData('Text', textToPutOnClipboard);    
    } else {
        e.clipboardData.setData('text/plain', textToPutOnClipboard);
    }
    e.preventDefault();
});

Перевод текста в буфер обмена не во время события с системной копией гораздо сложнее. Похоже, что некоторые из этих других ответов описывают способы сделать это через Flash, что является единственным кросс-браузерным способом сделать это (насколько я понимаю).

Помимо этого, в браузере есть несколько вариантов.

Это самый простой в IE, где вы можете получить доступ к объекту clipboardData в любое время из JavaScript через:

window.clipboardData

(Если вы попытаетесь сделать это за пределами случая вырезания, копирования или вставки системы, IE будет предлагать пользователю предоставить разрешение на буфер обмена веб-приложений.)

В Chrome вы можете создать расширение Chrome, которое даст вам разрешения буфера обмена (это то, что мы делаем для Lucidchart). Затем для пользователей с установленным расширением вам просто нужно запустить системное событие самостоятельно:

document.execCommand('copy');

Похоже, Firefox некоторые варианты которые позволяют пользователям предоставлять разрешения определенным сайтам для доступа к буферу, но я не пробовал ни одного из них лично.


65



clipboard.js is a small, non-flash, utility that allows copying of text or html data to the clipboard. It's very easy to use, just include the .js and use something like this:

<button id='markup-copy'>Copy Button</button>

<script>
document.getElementById('markup-copy').addEventListener('click', function() {
  clipboard.copy({
    'text/plain': 'Markup text. Paste me into a rich text editor.',
    'text/html': '<i>here</i> is some <b>rich text</b>'
  }).then(
    function(){console.log('success'); },
    function(err){console.log('failure', err);
  });

});
</script>

clipboard.js is also on GitHub


42



ZeroClipboard is the best cross-browser solution I've found:

<div id="copy" data-clipboard-text="Copy Me!">Click to copy</div>    
<script src="ZeroClipboard.js"></script>
<script>
  var clip = new ZeroClipboard( document.getElementById('copy') );
</script>

If you need non-flash support for iOS you just add a fall-back:

clip.on( 'noflash', function ( client, args ) {
    $("#copy").click(function(){            
        var txt = $(this).attr('data-clipboard-text');
        prompt ("Copy link, then click OK.", txt);
    });
});  

http://zeroclipboard.org/

https://github.com/zeroclipboard/ZeroClipboard


35



Here is my take on that one..

function copy(text) {
    var input = document.createElement('input');
    input.setAttribute('value', text);
    document.body.appendChild(input);
    input.select();
    var result = document.execCommand('copy');
    document.body.removeChild(input)
    return result;
 }

29