Как известно, скопировать текст можно сочетаниями клавиш Ctrl|Cmd + С (вырезать - Ctrl|Cmd + X), а вставить - с помощью Ctrl|Cmd + V. В JavaScript этим комбинациям соответствуют события oncopy (oncut) и onpaste. Все эти операции задействуют буфер обмена и Clipboard API в JavaScript.
С точки зрения написания скрипта, обрабатывающего события copy/cut/paste можно использовать свойство объекта Event или объекта window (для Internet Explorer) с названием clipboardData и его методы или свойство объекта navigator clipboard и его методы.
Давайте рассмотрим оба подхода.
- Свойство
clipboardDataв функции-обработчике события - Clipboard API. Использование объекта Navigator
- Использование document.execCommand
Свойство clipboardData в функции-обработчике события
Для того чтобы работать с буфером обмена, можно использовать методы getData() при копировании и setData() при вставке. Для этого в функции-обработчике события указывают параметр, связанный с объектом Event и используют его в коде.
Метод getData()
Метод getData()считывает данные из буфера обмена и выводит их. В качестве параметра ожидается формат данных (в виде строки). Для этого в качестве первого параметра необходимо указать формат данных. Здесь возможны "text/plain" (текстовые данные) или "text/html" (текст с тегами).
Но сначала эти данные обычно надо записать в буфер обмена, поэтому мы используем метод setData().
Метод setData()
Метод setData()записывает данные в буфер обмена. В качестве первого параметра используем такие же варианты формата, что и в getData(), a вторым - нужный текст.
В примере ниже вы найдете использование обоих методов при копировании и вставке текста из массива с фразами.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | const text = ["Copy and Paste", "Hello world!", "Close your eyes", "Look forward", "Don't give up!", "Let's go!","Copied with Ctrl+C", "Paste with Ctrl+V"]; const randNum = () => parseInt(Math.random()*text.length); document.addEventListener("copy", (e) => { e.preventDefault(); // Prevent default copy behavior e.clipboardData.setData("text/plain", text[randNum()]); }); document.addEventListener("paste", (e) => { e.preventDefault(); // Prevent default paste behavior const textToPaste = e.clipboardData.getData("text/plain"); temp.value = textToPaste; }); |
Для тестирования нажмите последовательно Ctrl+C и Ctrl+V.
See the Pen copy&paste with clipboard by Elen (@ambassador) on CodePen.
Пример с копированием текста и вставкой его в верхнем регистре.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <div class="source">Выделите и скопируйте этот текст</div> <div class="output" contenteditable="true">Вставить надо сюда!</div> <script> document.addEventListener("copy", (event) => { const selection = document.getSelection(); event.clipboardData.setData("text/plain", selection.toString().toUpperCase()); event.preventDefault(); }); document.addEventListener("paste", (event) => { event.preventDefault(); output.innerHTML = event.clipboardData.getData("text/plain"); }); </script> |
Давайте попробуем:
See the Pen Clipboard API by HTML-plus (@ambassador) on CodePen.
Копирование изображений с помощью clipboardData.files
В том случае, если вы захотите, например, скопировать изображение с помощью контекстного меню браузера, вы можете также воспользоваться свойством clipboardData.files. Для вставки вам понадобится использовать объект FileReader для того, чтобы прочитать содержимое скопированного файла.
JS-код примера:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | let img = document.getElementById("clipboard-image"), filename = document.getElementById("filename"); document.onpaste = function(event) { let data = event.clipboardData || window.clipboardData; if (data.files.length) { let file = data.files[0]; if (file.type.startsWith("image/")) { let reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function() { img.setAttribute("src", reader.result); filename.innerText = file.name; } } } }; |
Пример в действии:
See the Pen Clipboard API by HTML-plus (@ambassador) on CodePen.
Обратите внимание, что вы получаете файл image.png, хотя копируете ОЗУП-изображение. Если вы захотите сохранить скопированное изображение, оно также будет в формате PNG.
Clipboard API. Использование объекта Navigator
Данные в буфер обмена можно записать и получить также с помощью объекта Navigator. В этом случае вы можете использовать методы readText() и writeText() для копирования/вырезания/вставки текста и методы write() и read() для изображения.
Доступные форматы для чтения и записи файлов:
| Тип/Формат | Пояснение |
|---|---|
| text/plain | Обычный текст |
| text/html | HTML-разметка (текст с тегами) |
| image/png | Изображение в png-формате |
Ранее допустимыми типами данных также были text/uri-list, text/csv, image/svg+xml, application/xml, text/xml, application/json, но на данный момент с спецификации оставлены только 3, перечисленные в таблице, в связи с соображениями безопасности.
В этом способе есть одно ограничение - пользователю нужно разрешить использование работы с navigator.clipboard. Выглядит оно в виде такого диалогового окна (на примере работы с сайтом codepen.io).
Если пользователь заблокирует просмотр текста, то и воспользоваться функционалом Clipboard API не получится.
Еще один нюанс работы с Clipboard API основан на том, что вы используете в этом случае промисы, поэтому получить данные можно будет только после небольшого ожидания. И сам код должен быть написан либо с использованием методов then() и catch(), либо асинхронных функций. Также можно использовать конструкцию try...catch.
Копирование текста
Само по себе копирование может осуществляться как при клике на кнопку, так и при нажатии клавиш Ctrl+C. Вставить текст вы можете, как непосредственно кодом в нужный момент, так и при клике на кнопку/нажатии клавиш Ctrl+V.
В примере ниже мы копируем ссылку в буфер обмена при клике на кнопку и сразу вставляем в абзац ниже кнопки, но при этом нажатие клавиш Ctrl+V добавит вам эту ссылку в любой текстовый редактор.
| 1 2 3 4 5 6 7 8 9 | async function copyPageUrl() { try { await navigator.clipboard.writeText(location.href); console.log('Ссылка скопирована в буфер обмена'); outputURL.innerHTML = `<a href="${await navigator.clipboard.readText()}">Ссылка на данную страницу</a>`; } catch (err) { console.error('Проблема с копированием: ', err); } } |
Попробуйте сами:
Как добавить ссылку на вашу страницу при копировании текста, читайте в отдельной статье.
В примере ниже мы будем копировать и вставлять текст с помощью клика по кнопкам. Как видно из кода, мы сначала получаем текст, введенный пользователем в текстовое поле с id="textCopy", а в функции then() выводим сообщение об этом.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | function copyText() { let val = document.getElementById("textCopy").value; navigator.clipboard.writeText(val) .then(function() { alert(`Текст ${val} скопирован в clipboard`); }); } function pasteText() { navigator.clipboard.readText() .then(function(clipText) { document.getElementById("textPaste").value = clipText; }).catch(function() { alert("Доступ к clipboard запрещен"); }); } |
При вставке текста вы либо увидите сам текст, либо сообщение о том, что доступ к clipboard запрещен. Настройки по включению/выключению этого доступа в браузере Chrome вы найдете слева в строке адреса.
Сам пример:
See the Pen Clipboard API by HTML-plus (@ambassador) on CodePen.
Примерно тот же подход мы используем для обработки событий copy и paste, но с асинхронной функцией. Не забудьте разрешить действия с буфером обмена.
| 1 2 3 4 5 6 7 8 9 | document.addEventListener('copy', async () => { const val = await navigator.clipboard.writeText(copyText.value); pasteText.select(); alert('Скопировано!'); }) document.addEventListener('paste', async () => { const copiedValue = await navigator.clipboard.readText(); pasteText.value = copiedValue; }) |
Тут вы видите асинхронную функцию, которая при нажатии CTRL+C получает значение из текстового поля и записывает его строкой navigator.clipboard.writeText(copyText.value).
Затем при нажатии CTRL+V это значение вставляется в текстовое поле внизу.
See the Pen Clipboard API (navigator.clipboard property) by Elen (@ambassador) on CodePen.
Копирование выделенного текста
В примере ниже вы найдете, как с помощью свойства navigator.clipboard скопировать и вставить только выделенный текст или весь текст блока, если выделения текста не было. Для этого вам нужно, соответственно, либо выделить текст и нажать на кнопку Copy, либо нажать эту кнопку, ничего не выделяя.
При нажатии на CTRL + V вы увидите либо выделенный/полный текст из серого блока внутри элемента textarea, либо сообщение об ошибке, если у вас отсутствует разрешение на работу с буфером обмена через объект navigator.
See the Pen Copy/Paste text/text range with button by Elen (@ambassador) on CodePen.
Копирование изображения
При копировании и вставке изображения нам понадобится несколько более сложный скрипт, чем при копировании и вставке текста. Но и здесь у нас есть несколько вариантов.
Первый скрипт вообще не подразумевает использование Clipboard API, зато подразумевает использование события copy и объекта типа FileReader, a также Fetch API, которая позволяет загружать файлы изображений, получая их данные в формате Blob - именно такие, которые нужны для FileReader.
В примере ниже вам надо выбрать, какое изображение вы будете копировать, и блок внизу, в который оно будет добавлено. Сочетание клавиш CTRL+С генерирует нам событие copy, а добавление изображения в блок создает скрипт.
See the Pen Copy and Paste Image with FileReader in JS by HTML-plus (@ambassador) on CodePen.
Cкрипт в примере ниже помогает понять, как мы можем использовать Clipboard API вместе с отрисовкой изображений в canvas. Для изображений мы можем использовать только формат image/png, поэтому все многообразие изображений нам надо перевести в этот формат с помощью canvas. Кроме того, метод writeText() уже не подходит в силу отсутствия текста, поэтому нужно использовать метод write() и создавать новый тип данных с помощью конструктора new ClipboardItem:
| 1 2 3 4 5 | navigator.clipboard.write([ new ClipboardItem({ [blob.type]: blob }) ]); |
Попробуйте сами скопировать с помощью Ctrl+С любое из изображений в верхнем ряду и вставить его (их) в любой из нижних блоков с помощью Ctrl+V.
See the Pen Copy and Paste Image with Clipboard API in JS by HTML-plus (@ambassador) on CodePen.
В примере ниже на той же основе рисования в canvas вы можете скопировать случайное изображение с ресурcа unsplash.com и сочетанием клавиш Ctrl + V вставить его вместо уже существующего изображения.
See the Pen Clipboard API copy-paste image by Elen (@ambassador) on CodePen.
Процесс копирования и вставки изображения в примере ниже основан на получении данных из объекта типа Blob при использовании метода URL.createObjectURL.
See the Pen paste event with navigator.clipboard.read() by HTML-plus (@ambassador) on CodePen.
Ниже вы найдете код от Sten Hougaard, позволяющий копировать изображения из вашей файловой системы и вставлять их в html-элементы.
See the Pen HTML5 paste image to page by Sten Hougaard (@netsi1964) on CodePen.
Использование document.execCommand
Традиционным способом получения доступа к системному буферу обмена ранее было использование document.execCommand() для взаимодействия с буфером обмена. Этот метод позволял выполнять операции копирования (document.execCommand("copy")), вырезания (document.execCommand("cut")) и вставки (document.execCommand("paste")), но осуществлял только синхронный доступ к буферу обмена, а также мог только читать и писать в DOM.
Это нормально для небольших фрагментов текста, но во многих случаях блокировать страницу для передачи из буфера обмена нежелательно. Прежде чем можно будет безопасно вставить контент, может потребоваться трудоемкая очистка или декодирование изображений. Браузеру может потребоваться загрузить или встроить связанные ресурсы из вставленного документа. Это заблокирует страницу во время ожидания на диске или в сети.
Тем не менее вы можете найти в сети массу примеров с использованием метода document.execCommand(), которые будут вполне работоспособны и на данный момент. Например, ниже есть код для копирования в буфер обмена длинного текста (токена, SSL-сертификата и т.п.) с помощью document.execCommand("copy") от Or.
See the Pen token copy by Or (@oraricha) on CodePen.
Данный пример предполагает, что вы вставите скопированный текст куда-либо, кроме текущего документа: на другую страницу, в текстовый редактор и т.п.
Похожий пример с копированием email:
See the Pen JavaScript copy to clipboard by HTML-plus (@ambassador) n CodePen.
Еще один пример от Geoffrey Crofte с document.execCommand("copy"), но с возможностью сразу же вставить текст в другое поле.
See the Pen Copy in clipboard with JavaScript by Geoffrey Crofte (@GeoffreyCrofte) on CodePen.
И еще одно практическое применение document.execCommand("copy") - конвертер svg в css-свойство background-image с возможностью скопировать результат. Применимо, например, для создания стрелок в карусели (слайдере).
See the Pen Convert SVG to Data URI for css background-image by Ruskinz (@elliz) on CodePen.
Недостаточно информации? Посмотрите еще здесь.