Решение № 1 (только обычный текст, требуется Firefox 22+)
Работает для IE6 +, FF 22+, Chrome, Safari, Edge (протестировано только в IE9 +, но должно работать для более низких версий)
Если вам нужна поддержка для вставки HTML или Firefox <= 22, см. Решение № 2.
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)
Протестировано в 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
содержит ли его свойство 'text / html' (это types
может быть либо DOMStringList
проверяемый с помощью contains
метода, либо строка, проверяемая с помощью этого indexOf
метода). Если все эти условия выполнены, то мы поступаем так же, как в решении № 1, за исключением «text / html» вместо «text / plain». В настоящее время это работает в Chrome и Firefox 22+.
Если этот метод не поддерживается (все остальные браузеры), то мы
- Сохраните содержимое элемента в
DocumentFragment
- Очистить элемент
- Вызвать
waitForPastedData
функцию
waitforpastedata
Функция:
Эта функция сначала запрашивает вставленные данные (один раз в 20 мс), что необходимо, поскольку они не отображаются сразу. Когда появились данные это:
- Сохраняет innerHTML редактируемого div (который теперь является вставленными данными) в переменную
- Восстанавливает содержимое, сохраненное в DocumentFragment
- Вызывает функцию processPaste с полученными данными.
processpaste
Функция:
Делает произвольные вещи с вставленными данными. В этом случае мы просто оповещаем данные, вы можете делать все что угодно. Возможно, вы захотите запустить вставленные данные через какой-то процесс очистки данных.
Сохранение и восстановление позиции курсора
В реальной ситуации вы, вероятно, захотите сохранить выделение раньше, а затем восстановить его ( установите позицию курсора на contentEditable <div> ). Затем вы можете вставить вставленные данные в положение, в котором находился курсор, когда пользователь инициировал действие вставки.
Ресурсы:
Спасибо Тиму Дауну за предложение использовать DocumentFragment и облегчить обнаружение ошибки в Firefox из-за использования DOMStringList вместо строки для clipboardData.types