Доступ к буферу обмена ОС с помощью браузера JavaScript возможен уже несколько лет document.execCommand().
К сожалению, есть некоторые проблемы:
- доступ к буферу обмена является синхронным, что влияет на производительность и безопасность;
- поддержка неоднородна, особенно в старых версиях Safari на macOS и iOS;
- доступ к разрешениям различается в зависимости от браузера;
- API никогда не мог считаться элегантным;
Наконец, его заменил новый API асинхронного буфера обмена. Он новый, и ни один браузер не поддерживает все функции, но он проще в использовании и надёжнее.
Зачем приложению нужен доступ к буферу обмена?
Как разработчик вы знаете, как работает буфер обмена, и регулярно используете следующие сочетания клавиш:
- Ctrl| Cmd+ C копировать.
- Ctrl| Cmd+ X вырезать.
- А также Ctrl| Cmd+ V вставить.
Те, у кого меньше опыта работы с компьютером, необязательно будут обладать этими знаниями. Они также могут использовать устройство с сенсорным экраном, на котором недоступны сочетания клавиш. Предлагая простые в использовании значки вырезания и вставки, может быть полезно.
Кроме того, вы можете изменить содержимое после завершения действия с буфером обмена, например, добавления или удаления форматирования.
Доступ к буферу обмена опасен!
Программный доступ к буферу обмена вызывает несколько проблем с безопасностью:
Пользователи часто копируют пароли или личную информацию, поэтому ни одна страница не может произвольно читать данные из буфера обмена.
Страницы должны быть ограничены при добавлении данных в буфер обмена. Подлая страница может заменить скопированный текст опасной командой или даже исполняемым файлом.
Чтобы избежать потенциальных проблем, API буфера обмена можно использовать только на страницах, обслуживаемых через HTTPS ( localhostтакже разрешено). При запуске в iframe родительская страница также должна предоставлять clipboard-readи / или clipboard-writeразрешения:
<iframe src="childpage.html" allow="clipboard-read; clipboard-write" ></iframe>
API доступен только для активной вкладки браузера (не для фоновых вкладок) и может быть запущен только при взаимодействии с пользователем, например, щелчком. При необходимости пользователю будет предложено разрешение на чтение данных из буфера обмена:
Это предупреждение отображается, когда страница впервые запрашивает доступ к буферу обмена. Это не должно вызывать никаких проблем, учитывая, что API асинхронный и возвращает обещание. А также можно проверить и запросить статус с помощью API разрешений.
Обнаружение функции API буфера обмена
API буфера обмена доступен, когда navigator.clipboardвозвращает правдивый результат. Например:
if (navigator.clipboard) { console.log('Clipboard API available'); }
Однако это не гарантирует, что браузер поддерживает все функции, поэтому необходимо выполнить дополнительные проверки. Например, на момент написания Chrome поддерживает метод API readText (), а Firefox — нет.
Копировать и вставить текст
Копирование и вставка текста будет полезным вариантом в большинстве приложений. API очень прост:
// copy text TO the clipboard await navigator.clipboard.writeText('This text is now in the clipboard'); // get text FROM the clipboard let text = await navigator.clipboard.readText();
Вам потребуется значительно больше кода для обнаружения поддержки и обработки ошибок.
В этом примере реализуется копирование текста, когда к data-copyатрибуту добавляется любой элемент HTML, например кнопка. Вы можете установить это значение на одно из следующих значений:
- Жёстко запрограммированная строка, например data-copy=»copy this to the clipboard».
- Селектор CSS, например data-copy=»#mysection«. Затем копируется текстовое содержимое первого совпадающего элемента.
При желании вы можете установить собственное сообщение об успешном завершении в data-done атрибуте:
<button data-copy="#mysection" data-done="section copied"> copy text from #mysection </button>
Кнопка отображается только тогда, когда navigator.clipboard.writeText()поддерживается. При нажатии обработчик событий JavaScript находит текст, копирует его в буфер обмена и показывает анимированное сообщение об успешном завершении.
Кнопка вставки текста очень похожа, за исключением того, что она определяет data-pasteатрибут, который должен указывать на узел DOM:
<textarea id="pastehere"></textarea> <button data-paste="#pastehere">paste</button>
Копировать и вставлять данные
Clipboard API, readText()и writeText()варианта удобства для более общих read()и write()методов. У них меньше поддержки браузером, но они могут копировать и вставлять любые типы данных, например двоичные изображения.
Для копирования требуются данные большого двоичного объекта, обычно возвращаемые методом fetch()или canvas.toBlob(). Это передаётся ClipboardItemконструктору, чтобы его можно было записать в буфер обмена:
const image = await fetch('myimage.png'), blob = await image.blob(); await navigator.clipboard.write([ new ClipboardItem({ [blob.type]: blob }) ]);
Вставка более сложна, поскольку ClipboardItemможно возвращать несколько объектов с разными типами содержимого. Поэтому необходимо перебирать каждый тип, пока не будет найден полезный формат. Например:
const clipboardItems = await navigator.clipboard.read(); for (const clipboardItem of clipboardItems) { for (const type of clipboardItem.types) { if (type === 'image/png') { // return PNG blob return await clipboardItem.getType(type); } } }
Это работает аналогично текстовой демонстрации, в этой копии и вставить кнопки должны указывать на элементы DOM, используя селектор CSS в data-copyblobи data-pasteblobатрибутов. Например:
<!-- copy image --> <img id="myimage" src="myimage.png" alt="any image" /> <button data-copyblob="#myimage" data-done="image copied"> copy image </button> <!-- paste into DOM --> <div id="imagelist"></div> <button data-pasteblob="#imagelist"> paste image </button>
Попробуйте скопировать данные изображения из графического приложения, затем используйте кнопку вставки.
Вырезать, скопировать и вставить события
События cut, copyи pasteсрабатывают всякий раз, когда пользователь инициирует действие с буфером обмена в браузере — обычно с помощью контекстного меню или сочетаний клавиш, упомянутых выше. Это поддерживается в большинстве браузеров, и функции обработчика могут перехватывать события для внесения изменений с использованием clipboardDataобъекта, переданного в качестве параметра.
Следующая функция переводит весь вырезанный или скопированный текст в верхний регистр. Обратите внимание, что это e.preventDefault() останавливает действие вырезания / копирования по умолчанию, которое переопределит его:
body.addEventListener('cut', cutCopyHandler); body.addEventListener('copy', cutCopyHandler); // cut or copy event handler function cutCopyHandler(e) { const selection = document.getSelection(); // send uppercase text to clipboard e.clipboardData.setData( 'text/plain', selection.toString().toUpperCase() ); if (e.type === 'cut') selection.deleteFromDocument(); // stop default cut/copy e.preventDefault(); }
Следующий код прикрепляет обработчик вставки к определенному <textarea>полю. Функция очищает существующее содержимое и добавляет префиксы к тексту «pasted:»:
document.getElementById(‘field1’).addEventListener(‘paste’, pasteEvent);
document.getElementById('field1').addEventListener('paste', pasteEvent); // paste event handler function pasteEvent(e) { // add 'pasted:' to pasted text const paste = 'pasted:\n' + (e.clipboardData || window.clipboardData).getData('text'); e.target.value = paste; // stop default paste e.preventDefault(); }
Заключение
API буфера обмена является новым, но имеет разумную поддержку браузера и кажется более надежным, чем старый document.execCommand()вариант.
Лучше всего добавлять его как прогрессивное усовершенствование, поэтому функции вырезания, копирования и вставки будут реализованы в вашем приложении только тогда, когда они доступны.