今天來看 Events 的部分,Event 的使用方式就和 JavaScript 的事件監聽一樣,透過指定的事件名稱來監聽,並執行指定的方法。

text-change

text-change 事件在編輯器的內容發生變化時觸發。變更的細節、變更前的內容,以及變更的來源都會提供出來。來源如果是使用者觸發的,則 source 就會是 user。例如:

  • 使用者在編輯器中打字
  • 使用者使用工具列格式化文字
  • 使用者使用快捷鍵回上一步
  • 使用者使用作業系統拼寫校正

特例:
觸發內容變更的事件雖然也可能透過 API 呼叫,但如果觸發的原因是使用者操作導致的話,source 仍然要設為 user。舉個例子:當使用者點擊工具欄的模組功能,該模組會呼叫變更的 API,但由於是使用者點擊所造成的變化,因此我們在模組呼叫 API 的時候,帶入的 source 仍必須是 user

Silent Source:
呼叫 API 處理的內容變更也可能以 sourcesilent 的方式觸發,在這樣的情況下 text-change 將不會被觸發。不建議這樣的操作,因為這樣可能會導致撤銷的堆疊紀錄異常,或是間接影響到需要完整內容變化紀錄的功能。

選取 (Selection) 發生變化
文字內容的變化可能導致 selection 變化(例如,打字使游標前進),但是在 text-change handler 執行期間,selection 尚未更新,加上原生瀏覽器的行為可能導致 selection 狀態不一致的情況。因此要使用 selection-changeeditor-change 來處理 selection 更新比較穩定。

Callback Signature:

handler(delta: Delta, oldContents: Delta, source: String)

範例:

quill.on('text-change', function(delta, oldDelta, source) {
  if (source == 'api') { 
    console.log("An API call triggered this change.");
  } else if (source == 'user') { 
    console.log("A user action triggered this change."); 
  } 
});

selection-change

當使用者或 API 造成 selection 變更時觸發,range 代表 selection 的邊界。當 rangenull 時,表示 selection 的丟失(通常是由於編輯器失去焦點)。我們也可以在收到 rangenull 的時候,用這個事件當作焦點變更的 event 確認。

API 造成的選取範圍變更也可能會以 sourcesilent 觸發,在這樣的情況下就不會觸發 selection-change。如果 selection-change 是 side effect 的話就很有用。例如:輸入文字造成 selection 變更,但每個字元都觸發 selection-change 的話就可能會造成干擾。

Callback Signature:

handler(range: { index: Number, length: Number },
        oldRange: { index: Number, length: Number },
        source: String)

範例:

quill.on('selection-change', function(range, oldRange, source) {
  if (range) { 
    if (range.length == 0) {
      console.log('User cursor is on', range.index);
    } else { 
      const text = quill.getText(range.index, range.length);
      console.log('User has highlighted', text);
    } 
  } else { 
    console.log('Cursor not in the editor'); 
  }
});

editor-change

當觸發 text-changeselection-change 事件時,也會跟著觸發 editor-change,即使 sourcesilent 也是一樣。第一個參數是事件名稱,不是 text-change 就是 selection-change,之後的通常是傳遞給這些相應的 handler 參數。

Callback Signature:

handler(name: String, ...args)

範例:

quill.on('editor-change', function(eventName, ...args) {
  if (eventName === 'text-change') { 
    // args[0] will be delta 
  } else if (eventName === 'selection-change') {
    // args[0] will be old range 
  }
});

on

監聽特定的事件並加入 event handler。

方法:

on(name: String, handler: Function): Quill

範例:

quill.on('text-change', function() {
  console.log('Text change!'); 
});

once

為事件的一次觸發加入 event handler。

方法:

once(name: String, handler: Function): Quill

範例:

quill.once('text-change', function() {
  console.log('First text change!');
});

off

移除 event handler

方法:

off(name: String, handler: Function): Quill

範例:

function handler() { 
  console.log('Hello!');
}
quill.on('text-change', handler);
quill.off('text-change', handler);

小結

Quill 提供了三種事件監聽類型分別是 text-changeselection-change,以及 editor-change,整理一下今天練習的 event 方法:

  • text-change:內容變化時觸發,包括使用者操作或API呼叫等。
  • selection-change:選取範圍變更時觸發,提供選取的邊界,也能作為焦點變更的事件。
  • editor-change:結合觸發 text-changeselection-change 的變更。
  • on:根據監聽類型加入對應的事件處理器。
  • once:根據監聽類型加入只執行一次的事件處理器。
  • off:移除事件處理器。

雜記

前幾天在 DefinitelyTyped 提的 Quill PR 終於合併了,目前只要重新 npm install 就能夠把 OP 類型錯誤的問題解決了,要確認一下 types 的版本是 2.0.12。久違的 OpenSource contribution XD 希望對大家有所幫助 :D

Reference

文章同步發表於2023 iThome 鐵人賽