Javascript - Скопировать строку в буфер обмена в виде текста / HTML
Есть ли способ в javascript, чтобы скопировать строку html (т.е. <b>xx<b>
) в буфер обмена в виде text / html, чтобы затем его можно было вставить, например, в сообщение gmail с форматированием (т. е. xx выделено жирным шрифтом)
Существуют решения для копирования в буфер обмена в виде текста (text / plain), например, /questions/14172016/kak-mne-skopirovat-v-bufer-obmena-v-javascript/14172024#14172024 но не в виде text / html.
Мне нужно решение без flash, без jquery, которое будет работать по крайней мере на IE11 FF42 и Chrome.
В идеале я хотел бы сохранить текстовую и HTML-версии строки в буфере обмена, чтобы можно было вставить нужную версию в зависимости от того, поддерживает ли цель HTML или нет.
6 ответов
Я сделал несколько изменений в ответе Лойло выше:
установка (и последующее восстановление) фокуса на скрытый div предотвращает бесконечную рекурсию FF при копировании из текстовой области
установка диапазона для внутренних дочерних элементов div предотвращает добавление хрома
<br>
в началеremoveAllRanges в getSelection() предотвращает добавление к существующему выбору (возможно, не требуется)
попробуйте / поймать вокруг execCommand
лучше скрывать копию div
На OSX это не будет работать. Safari не поддерживает execCommand, а в chrome OSX есть известная ошибка https://bugs.chromium.org/p/chromium/issues/detail?id=552975
код:
clipboardDiv = document.createElement('div');
clipboardDiv.style.fontSize = '12pt'; // Prevent zooming on iOS
// Reset box model
clipboardDiv.style.border = '0';
clipboardDiv.style.padding = '0';
clipboardDiv.style.margin = '0';
// Move element out of screen
clipboardDiv.style.position = 'fixed';
clipboardDiv.style['right'] = '-9999px';
clipboardDiv.style.top = (window.pageYOffset || document.documentElement.scrollTop) + 'px';
// more hiding
clipboardDiv.setAttribute('readonly', '');
clipboardDiv.style.opacity = 0;
clipboardDiv.style.pointerEvents = 'none';
clipboardDiv.style.zIndex = -1;
clipboardDiv.setAttribute('tabindex', '0'); // so it can be focused
clipboardDiv.innerHTML = '';
document.body.appendChild(clipboardDiv);
function copyHtmlToClipboard(html) {
clipboardDiv.innerHTML=html;
var focused=document.activeElement;
clipboardDiv.focus();
window.getSelection().removeAllRanges();
var range = document.createRange();
range.setStartBefore(clipboardDiv.firstChild);
range.setEndAfter(clipboardDiv.lastChild);
window.getSelection().addRange(range);
var ok=false;
try {
if (document.execCommand('copy')) ok=true; else utils.log('execCommand returned false !');
} catch (err) {
utils.log('execCommand failed ! exception '+err);
}
focused.focus();
}
см. jsfiddle, где вы можете ввести html-сегмент в текстовую область и скопировать в буфер обмена с помощью ctrl + c.
Поскольку этот ответ привлек некоторое внимание, я полностью переписал грязный оригинал, чтобы его было легче понять. Если вы хотите взглянуть на предварительно исправленную версию, вы можете найти ее здесь.
Сложенный вопрос:
Могу ли я использовать JavaScript, чтобы скопировать форматированный вывод некоторого HTML-кода в буфер обмена пользователя?
Ответ:
Да, с некоторыми ограничениями, вы можете.
Решение:
Ниже приведена функция, которая будет делать именно это. Я протестировал его с вашими необходимыми браузерами, он работает во всех из них. IE 11, тем не менее, запросит подтверждение этого действия.
Объяснение того, как это работает, можно найти ниже, вы можете в интерактивном режиме протестировать функцию в этом jsFiddle.
// This function expects an HTML string and copies it as rich text.
function copyFormatted (html) {
// Create container for the HTML
// [1]
var container = document.createElement('div')
container.innerHTML = html
// Hide element
// [2]
container.style.position = 'fixed'
container.style.pointerEvents = 'none'
container.style.opacity = 0
// Detect all style sheets of the page
var activeSheets = Array.prototype.slice.call(document.styleSheets)
.filter(function (sheet) {
return !sheet.disabled
})
// Mount the container to the DOM to make `contentWindow` available
// [3]
document.body.appendChild(container)
// Copy to clipboard
// [4]
window.getSelection().removeAllRanges()
var range = document.createRange()
range.selectNode(container)
window.getSelection().addRange(range)
// [5.1]
document.execCommand('copy')
// [5.2]
for (var i = 0; i < activeSheets.length; i++) activeSheets[i].disabled = true
// [5.3]
document.execCommand('copy')
// [5.4]
for (var i = 0; i < activeSheets.length; i++) activeSheets[i].disabled = false
// Remove the container
// [6]
document.body.removeChild(container)
}
Объяснение:
Посмотрите на комментарии в коде выше, чтобы увидеть, где вы находитесь в следующем процессе:
- Мы создаем контейнер для размещения нашего HTML-кода.
- Мы делаем стиль контейнера скрытым и определяем активные таблицы стилей страницы. Причина будет объяснена в ближайшее время.
- Мы помещаем контейнер в DOM страницы.
- Мы удаляем, возможно, существующие выборы и выбираем содержимое нашего контейнера.
Мы делаем само копирование. На самом деле это многошаговый процесс: Chrome будет копировать текст так, как он его видит, с применением стилей CSS, в то время как другие браузеры будут копировать его со стилями браузера по умолчанию. Поэтому мы отключим все пользовательские стили перед копированием, чтобы получить максимально согласованный результат.
- Прежде чем мы сделаем это, мы преждевременно выполняем
copy
команда. Это взлом для IE11: в этом браузере копирование должно быть подтверждено вручную один раз. Пока пользователь не нажмет кнопку "Подтвердить", пользователи IE будут видеть страницу без каких-либо стилей. Чтобы избежать этого, мы сначала копируем, ждем подтверждения, затем отключаем стили и снова копируем. На этот раз мы не получим диалоговое окно подтверждения, поскольку IE запоминает наш последний выбор. - Мы фактически отключаем стили страницы.
- Теперь мы снова выполним
copy
команда. - Мы снова включаем таблицы стилей.
- Прежде чем мы сделаем это, мы преждевременно выполняем
- Мы удаляем контейнер из DOM страницы.
И мы сделали.
Предостережения:
Отформатированный контент не будет идеально согласован в разных браузерах.
Как объяснено выше, Chrome (т. Е. Механизм Blink) будет использовать другую стратегию, нежели Firefox и IE: Chrome будет копировать содержимое с использованием своих стилей CSS, но исключая любые стили, которые не определены.
Firefox и IE, с другой стороны, не будут применять CSS для конкретной страницы, они будут применять стили браузера по умолчанию. Это также означает, что к ним будут применены некоторые странные стили, например, шрифт по умолчанию (обычно это Times New Roman).
Из соображений безопасности браузеры разрешают выполнение функции только в результате взаимодействия с пользователем (например, щелчок, нажатие клавиши и т. Д.)
Есть гораздо более простое решение. Скопируйте раздел своей страницы (элемент), чем скопируйте HTML.
С помощью этой простой функции вы можете скопировать все, что хотите (текст, изображения, таблицы и т. Д.) На свою страницу или весь документ в буфер обмена. Функция получает идентификатор элемента или сам элемент.
function copyElementToClipboard(element) {
window.getSelection().removeAllRanges();
let range = document.createRange();
range.selectNode(typeof element === 'string' ? document.getElementById(element) : element);
window.getSelection().addRange(range);
document.execCommand('copy');
window.getSelection().removeAllRanges();
}
Как пользоваться:
copyElementToClipboard(document.body);
copyElementToClipboard('myImageId');
Для тех, кто ищет способ сделать это с помощью ClipboardItem и не может заставить его работать, даже если для dom.events.asyncClipboard.clipboardItem установлено значение true, ответ можно найти на сайте nikouusitalo.com.
А вот мой рабочий код (проверено на Firefox 102).
const clipboardItem = new
ClipboardItem({'text/html': new Blob([html],
{type: 'text/html'}),
'text/plain': new Blob([html],
{type: 'text/plain'})});
navigator.clipboard.write([clipboardItem]).
then(_ => console.log("clipboard.write() Ok"),
error => alert(error));
Убедитесь, что вы пытаетесь вставить его в редактор форматированного текста, такой как gmail, а не в редактор простого текста/уценки, такой как stackoverflow.
Если вы хотите использовать новый API буфера обмена , используйтеwrite
метод, как показано ниже:
var type = "text/html";
var blob = new Blob([text], { type });
var data = [new ClipboardItem({ [type]: blob })];
navigator.clipboard.write(data).then(
function () {
/* success */
},
function () {
/* failure */
}
);
В настоящее время (сентябрь 2021 г.) проблема в том, что Firefox не поддерживает этот метод .
Прошло почти два года, и в настоящее время существует более простой способ добиться этого с помощью clipboard.js.
Для этого требуется современный браузер (Chrome 42+, Firefox 41+, Opera 29+, Internet Explorer 9+, Safari 10+), но он скрывает сложность вставки копий форматированного текста (намного меньше кода для записи):
1) Ссылка clipboard.js
2) Создайте кнопку и на ее обработчике кликов создайте как неформатированный, так и форматированный (форматированный) текст и используйте его в библиотеке для копирования в буфер обмена:
clipboard.copy({
"text/plain": "Normal text comes here",
"text/html": "<b>Normal text</b> comes <div style="color: blue;">here</div>"
})
.then(
function() {
// success code here
},
function(err) {
// failure code here
}
);