Рішення №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
може бути або a, DOMStringList
що перевіряється contains
методом, або рядок, що перевіряється за допомогоюindexOf
методом). Якщо всі ці умови виконуються, ми продовжуємо, як у рішенні №1, за винятком "text / html" замість "text / plain". Наразі це працює в Chrome та Firefox 22+.
Якщо цей метод не підтримується (всі інші браузери), то ми
- Збережіть вміст елемента в a
DocumentFragment
- Опустіть елемент
- Викличте
waitForPastedData
функцію
waitforpastedata
функція:
Ця функція спочатку опитує для вставлених даних (раз на 20 мс), що необхідно, оскільки воно не з’являється відразу. Коли дані з’являються, це:
- Зберігає внутрішнійHTML редагованого div (який тепер вставлені дані) до змінної
- Відновлює вміст, збережений у DocumentFragment
- Викликає функцію 'processPaste' з отриманими даними
processpaste
функція:
Чи довільні речі із вставленими даними. У цьому випадку ми просто попереджаємо дані, ви можете робити все, що завгодно. Ви, ймовірно, захочете запустити вкладені дані через якийсь процес санітарії даних.
Збереження та відновлення положення курсору
У реальній ситуації ви, ймовірно, хочете зберегти виділення раніше та відновити його після цього ( Встановіть позицію курсора на contentEditable <div> ). Потім можна вставити вкладені дані в положення, в якому знаходився курсор, коли користувач ініціював дію вставки.
Ресурси:
Завдяки Тіму Даун запропонував використовувати DocumentFragment та abligh для введення помилки у Firefox завдяки використанню DOMStringList замість рядка для clipboardData.types