Решение № 1 (только обычный текст и требуется Firefox 22+)
Работает для IE6 +, FF 22+, Chrome, Safari, Edge
(Проверено только в IE9 +, но должно работать для более низких версий)
Если вам нужна поддержка для вставки HTML или Firefox <= 22, см. Решение № 2. </p>
HTML
<div id='editableDiv' contenteditable='true'>Paste</div>
JavaScript
function handlePaste (e) {
var clipboardData, pastedData;
// Stop data actually being pasted into div
e.stopPropagation();
e.preventDefault();
// Get pasted data via clipboard API
clipboardData = e.clipboardData || window.clipboardData;
pastedData = clipboardData.getData('Text');
// Do whatever with pasteddata
alert(pastedData);
}
document.getElementById('editableDiv').addEventListener('paste', handlePaste);
JSFiddle: https://jsfiddle.net/swL8ftLs/12/
Обратите внимание, что это решение использует параметр «Текст» для функции getData
, которая является нестандартной. Однако на момент написания он работает во всех браузерах.
Решение № 2 (HTML и работает для Firefox <= 22) </h1>
Протестировано в IE6 +, FF 3.5+, Chrome, Safari, Edge
HTML
<div id='div' contenteditable='true'>Paste</div>
JavaScript
var editableDiv = document.getElementById('editableDiv');
function handlepaste (e) {
var types, pastedData, savedContent;
// Browsers that support the 'text/html' type in the Clipboard API (Chrome, Firefox 22+)
if (e && e.clipboardData && e.clipboardData.types && e.clipboardData.getData) {
// Check for 'text/html' in types list. See abligh's answer below for deatils on
// why the DOMStringList bit is needed. We cannot fall back to 'text/plain' as
// Safari/Edge don't advertise HTML data even if it is available
types = e.clipboardData.types;
if (((types instanceof DOMStringList) && types.contains("text/html")) || (types.indexOf && types.indexOf('text/html') !== -1)) {
// Extract data and pass it to callback
pastedData = e.clipboardData.getData('text/html');
processPaste(editableDiv, pastedData);
// Stop the data from actually being pasted
e.stopPropagation();
e.preventDefault();
return false;
}
}
// Everything else: Move existing element contents to a DocumentFragment for safekeeping
savedContent = document.createDocumentFragment();
while(editableDiv.childNodes.length > 0) {
savedContent.appendChild(editableDiv.childNodes[0]);
}
// Then wait for browser to paste content into it and cleanup
waitForPastedData(editableDiv, savedContent);
return true;
}
function waitForPastedData (elem, savedContent) {
// If data has been processes by browser, process it
if (elem.childNodes && elem.childNodes.length > 0) {
// Retrieve pasted content via innerHTML
// (Alternatively loop through elem.childNodes or elem.getElementsByTagName here)
var pastedData = elem.innerHTML;
// Restore saved content
elem.innerHTML = "";
elem.appendChild(savedContent);
// Call callback
processPaste(elem, pastedData);
}
// Else wait 20ms and try again
else {
setTimeout(function () {
waitForPastedData(elem, savedContent)
}, 20);
}
}
function processPaste (elem, pastedData) {
// Do whatever with gathered data;
alert(pastedData);
elem.focus();
}
// Modern browsers. Note: 3rd argument is required for Firefox <= 6
if (editableDiv.addEventListener) {
editableDiv.addEventListener('paste', handlepaste, false);
}
// IE <= 8
else {
editableDiv.attachEvent('onpaste', handlepaste);
}
JSFiddle: https://jsfiddle.net/nicoburns/wrqmuabo/23/
Объяснение
К событию onpaste
div
присоединена функция handlePaste
, которой передан единственный аргумент: объект event
для события вставки. Особый интерес для нас представляет свойство clipboardData
этого события, которое обеспечивает доступ к буферу обмена в не-браузерах. В IE эквивалент window.clipboardData
, хотя у него немного другой API.
См. Раздел ресурсов ниже.
Функция handlepaste
:
Эта функция имеет две ветви.
Первый проверяет наличие event.clipboardData
и проверяет, содержит ли его свойство types
текст / html (types
может быть либо DOMStringList
, который проверяется с использованием метода contains
, либо строка, проверяемая методом indexOf
). Если все эти условия выполнены, то мы поступаем так же, как в решении № 1, за исключением «text / html» вместо «text / plain». В настоящее время это работает в Chrome и Firefox 22+.
Если этот метод не поддерживается (все остальные браузеры), тогда мы
- Сохранить содержимое элемента в
DocumentFragment
- Очистить элемент
- вызов функции
waitForPastedData
Функция waitforpastedata
:
Эта функция сначала запрашивает вставленные данные (один раз в 20 мс), что необходимо, поскольку они не отображаются сразу. Когда появились данные, это:
- Сохраняет innerHTML редактируемого div (который теперь является вставленными данными) в переменную
- Восстанавливает содержимое, сохраненное в DocumentFragment
- Вызывает функцию 'processPaste' с полученными данными
Функция processpaste
:
Делает произвольные вещи с вставленными данными. В этом случае мы просто предупреждаем данные, вы можете делать все что угодно. Возможно, вы захотите запустить вставленные данные через какой-то процесс очистки данных.
Сохранение и восстановление позиции курсора
В реальной ситуации вы, вероятно, захотите сохранить выделение раньше, а затем восстановить его ( Установить позицию курсора на contentEditable ). Затем можно вставить вставленные данные в положение, в котором находился курсор, когда пользователь инициировал действие вставки.
Ресурсы:
Спасибо Тиму Дауну, предложившему использовать DocumentFragment и облегчившему обнаружение ошибки в Firefox вследствие использования DOMStringList вместо строки для clipboardData.types