javascript - contenteditable 內容可編輯變更事件
我想在用戶編輯具有 contenteditable 屬性的 div 內容時執行一個函數。onchange 事件的等效方法是什麼?
我正在使用 jQuery,所以任何使用 jQuery 的解決方案都是首選。謝謝!
答案#1
2022 更新
比單純使用 input 事件更接近的方式是類似以下的做法:
let shouldFireChange = false;
editor.addEventListener("input", function() {
shouldFireChange = true;
});
editor.addEventListener("focusout", function() {
if(shouldFireChange) {
shouldFireChange = false;
// add emulated 'onchange' code here
}
});
原始答案
我建議對可編輯元素觸發的主要事件附加監聽器,但您需要注意,keydown 和 keypress 事件會在內容本身改變之前觸發。這並不能涵蓋所有可能改變內容的方式:使用者也可以使用「剪下」「複製」和「貼上」功能,無論是在編輯菜單還是瀏覽器右鍵菜單中,因此您可能也需要處理 cut、copy 和 paste 事件。此外,使用者還可以拖放文字或其他內容,因此還有更多事件(例如 mouseup)。您可能希望作為後備方案輪詢元素的內容。
更新 2014年10月29日
HTML5 input 事件是長期的解決方案。在撰寫本文時,它已被當前的 Mozilla(從 Firefox 14 開始)和 WebKit/Blink 瀏覽器支持於 contenteditable 元素,但 IE 尚未支持。
示範:
document.getElementById("editor").addEventListener("input", function() {
console.log("input event fired");
}, false);<div contenteditable="true" id="editor">Please type something in here</div>示範: http://jsfiddle.net/ch6yn/2691/
答案#2
這裡有一個更高效的版本,它對所有可編輯內容使用 on。它是基於這裡的最佳答案改編的。
$('body').on('focus', '[contenteditable]', function() {
const $this = $(this);
$this.data('before', $this.html());
}).on('blur keyup paste input', '[contenteditable]', function() {
const $this = $(this);
if ($this.data('before') !== $this.html()) {
$this.data('before', $this.html());
$this.trigger('change');
}
});
專案在這裡:https://github.com/balupton/html5edit
答案#3
考慮使用 MutationObserver。這些觀察者是用來對 DOM 的變化做出反應的,同時作為 Mutation Events 的高效替代方案。
優點:
- 在發生任何變化時觸發,這很難像其他答案建議的那樣通過監聽鍵盤事件來實現。例如,以下所有操作都能很好地運作:拖放、斜體化、通過右鍵菜單的複製/剪切/粘貼。
- 以性能為設計理念。
- 簡單、直接的程式碼。相比於監聽十個事件的程式碼,監聽一個事件的程式碼更容易理解和除錯。
- Google 有一個很棒的突變摘要庫,這使得使用 MutationObservers 非常容易。
缺點:
- 需要非常新的版本的 Firefox (14.0+)、Chrome (18+) 或 IE (11+)。
- 新的 API 以理解
- 目前關於最佳實踐或案例研究的資訊還不多
了解更多:
- 我寫了一個小片段來比較使用 MutationObserver 與處理各種事件的方法。我使用了 balupton 的程式碼,因為他的答案獲得的最高票數。
- Mozilla 有一個關於 API 的優秀頁面
- 看看 MutationSummary 函式庫
答案#4
非 jQuery 快速且 粗糙 的回答:
function setChangeListener (div, listener) {
div.addEventListener("blur", listener);
div.addEventListener("keyup", listener);
div.addEventListener("paste", listener);
div.addEventListener("copy", listener);
div.addEventListener("cut", listener);
div.addEventListener("delete", listener);
div.addEventListener("mouseup", listener);
}
var div = document.querySelector("someDiv");
setChangeListener(div, function(event){
console.log(event);
});
答案#5
我已經像這樣修改了 lawwantsin 的答案,這對我有效。我使用 keyup 事件而不是 keypress,效果很好。
$('#editor').on('focus', function() {
before = $(this).html();
}).on('blur keyup paste', function() {
if (before != $(this).html()) { $(this).trigger('change'); }
});
$('#editor').on('change', function() {alert('changed')});
答案#6
兩個選項:
1) 對於現代(常青)瀏覽器: 「input」事件可作為「change」事件的替代方法。
https://developer.mozilla.org/zh-TW/docs/Web/Events/input
document.querySelector('div').addEventListener('input', (e) => {
// Do something with the "change"-like event
});
或
<div oninput="someFunc(event)"></div>
或(使用 jQuery)
$('div').on('click', function(e) {
// Do something with the "change"-like event
});
2) 為了兼顧 IE11 及現代(常青)瀏覽器: 這會監測 div 內元素的變化及其內容。
https://developer.mozilla.org/zh-TW/docs/Web/API/MutationObserver
var div = document.querySelector('div');
var divMO = new window.MutationObserver(function(e) {
// Do something on change
});
divMO.observe(div, { childList: true, subtree: true, characterData: true });
答案#7
const p = document.querySelector('p')
const result = document.querySelector('div')
const observer = new MutationObserver((mutationRecords) => {
result.textContent = mutationRecords[0].target.data
// result.textContent = p.textContent
})
observer.observe(p, {
characterData: true,
subtree: true,
})<p contenteditable>abc</p>
<div />