Giải pháp số 1 (Chỉ văn bản thuần túy và yêu cầu Firefox 22+)
Hoạt động cho IE6 +, FF 22+, Chrome, Safari, Edge (Chỉ được thử nghiệm trong IE9 +, nhưng nên hoạt động cho các phiên bản thấp hơn)
Nếu bạn cần hỗ trợ để dán HTML hoặc Firefox <= 22, hãy xem Giải pháp # 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);
Mã thông báo: https://jsfiddle.net/swL8ftLs/12/
Lưu ý rằng giải pháp này sử dụng tham số 'Văn bản' cho getData
chức năng, không chuẩn. Tuy nhiên, nó hoạt động trong tất cả các trình duyệt tại thời điểm viết.
Giải pháp số 2 (HTML và hoạt động cho Firefox <= 22)
Đã thử nghiệm trong 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/
Giải trình
Sự onpaste
kiện của hàm div
có handlePaste
chức năng gắn liền với nó và truyền một đối số duy nhất: event
đối tượng cho sự kiện dán. Quan tâm đặc biệt đối với chúng tôi là clipboardData
tài sản của sự kiện này cho phép truy cập clipboard trong các trình duyệt không có nghĩa là. Trong IE tương đương window.clipboardData
, mặc dù điều này có API hơi khác.
Xem phần tài nguyên dưới đây.
Các handlepaste
chức năng:
Hàm này có hai nhánh.
Lần đầu tiên kiểm tra sự tồn tại của event.clipboardData
và kiểm tra xem thuộc types
tính của nó có chứa 'text / html' không ( types
có thể là một DOMStringList
trong đó được kiểm tra bằng contains
phương thức hoặc một chuỗi được kiểm tra bằng indexOf
phương thức). Nếu tất cả các điều kiện này được đáp ứng, thì chúng tôi sẽ tiến hành như trong giải pháp số 1, ngoại trừ với 'text / html' thay vì 'text / plain'. Điều này hiện đang hoạt động trong Chrome và Firefox 22+.
Nếu phương pháp này không được hỗ trợ (tất cả các trình duyệt khác), thì chúng tôi
- Lưu nội dung của phần tử vào một
DocumentFragment
- Làm trống phần tử
- Gọi
waitForPastedData
hàm
Các waitforpastedata
chức năng:
Chức năng này lần đầu tiên thăm dò dữ liệu đã dán (một lần trong 20ms), điều này là cần thiết bởi vì nó không xuất hiện ngay lập tức. Khi dữ liệu đã xuất hiện:
- Lưu phần bên trong của div có thể chỉnh sửa (hiện là dữ liệu đã dán) vào một biến
- Khôi phục nội dung được lưu trong DocumentFragment
- Gọi hàm 'processPaste' với dữ liệu được truy xuất
Các processpaste
chức năng:
Có những thứ tùy ý với dữ liệu dán. Trong trường hợp này, chúng tôi chỉ cảnh báo dữ liệu, bạn có thể làm bất cứ điều gì bạn muốn. Bạn có thể sẽ muốn chạy dữ liệu đã dán thông qua một số loại quy trình vệ sinh dữ liệu.
Lưu và khôi phục vị trí con trỏ
Trong một tình huống bão hòa thực sự, có lẽ bạn sẽ muốn lưu lựa chọn trước đó và khôi phục nó sau đó ( Đặt vị trí con trỏ trên contentEditable <div> ). Sau đó, bạn có thể chèn dữ liệu đã dán vào vị trí con trỏ đang ở khi người dùng bắt đầu hành động dán.
Tài nguyên:
Cảm ơn Tim Down đã đề xuất sử dụng DocumentFragment và bỏ qua việc bắt lỗi trong Firefox do sử dụng DOMStringList thay vì một chuỗi cho clipboardData.types