Обзор
Существует три основных API браузера для копирования в буфер обмена:
- API асинхронного буфера обмена
[navigator.clipboard.writeText]
- Текстовая часть доступна в Chrome 66 (март 2018)
- Доступ асинхронный и использует Обещания JavaScript , могут быть написаны так, чтобы запросы безопасности (если отображаются) не прерывали JavaScript на странице.
- Текст можно скопировать в буфер обмена непосредственно из переменной.
- Поддерживается только на страницах, обслуживаемых по HTTPS.
- В Chrome 66 страницы в активных вкладках могут записываться в буфер обмена без запроса прав доступа.
document.execCommand('copy')
- Большинство браузеров поддерживают это по состоянию на апрель 2015 года (см. «Поддержка браузеров» ниже).
- Доступ является синхронным, т.е. останавливает JavaScript на странице до завершения, включая отображение и взаимодействие пользователя с любыми запросами безопасности.
- Текст читается из DOM и помещается в буфер обмена.
- Во время тестирования ~ апрель 2015 г. только Internet Explorer был отмечен как отображающий запросы разрешений при записи в буфер обмена.
- Переопределение события копирования
- См. Документацию API буфера обмена по Переопределение события копирования .
- Позволяет изменить то, что появляется в буфере обмена, из любого события копирования, может включать в себя другие форматы данных, кроме обычного текста.
- Здесь не рассматривается, так как это не дает прямого ответа на вопрос.
Общие замечания по разработке
Не ожидайте, что команды, связанные с буфером обмена, будут работать, пока вы тестируете код в консоли. Обычно страница должна быть активной (Async Clipboard API) или требует взаимодействия с пользователем (например, щелчок пользователя), чтобы разрешить (document.execCommand('copy')
) доступ к буферу обмена, подробнее см. Ниже.
Async + Fallback
Из-за уровня поддержки браузером нового Async Clipboard API вы, вероятно, захотите вернуться к методу 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>
Обратите внимание, что этот фрагмент не работает должным образом во встроенном предварительном просмотре Stack Overflow, вы можете попробовать его здесь: https://codepen.io/DeanMarkTaylor/pen/RMRaJX?editors=1011
Async Clipboard API
Обратите внимание, что в Chrome 66 имеется возможность «запросить разрешение» и проверить доступ к буферу обмена через API разрешений.
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 и Internet Explorer 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
// Internet Explorer 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 с ~ апреля по ~ октябрь 2015 года возвратил true
из document.queryCommandSupported('copy')
, только если команда была вызвана из потока, инициированного пользователем.
Обратите внимание на подробности совместимости ниже.
Сведения о совместимости браузера
Хотя простой вызов document.execCommand('copy')
, заключенный в блок try
/ catch
, вызываемый в результате щелчка пользователя, обеспечит вам наибольшую совместимость, использование следующих условий имеет некоторые условия:
Любой вызов document.execCommand
, document.queryCommandSupported
или document.queryCommandEnabled
должен быть заключен в блок try
/ catch
.
Различные реализации браузера и версии браузера выдают различные типы исключений при вызове вместо возврата false
.
Различные реализации браузера все еще находятся в движении, а API буфера обмена все еще находится в стадии разработки, поэтому не забудьте провести тестирование.