網站搜尋

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 />