插入編輯內容 - daniel-qa/Vue GitHub Wiki
wangEditor 透過 this.savedRange.insertNode(node) 直接操作 DOM。
wangEditor 的編輯區域是一個 contenteditable 的 div,裡面就是普通的 DOM 樹。
savedRange 是指向這個 DOM 樹內某個位置的 Range 物件,所以:
savedRange.insertNode(node0)
等同於直接把 node0 這個 text node 插入到編輯器 DOM 樹的對應位置,編輯器畫面就會即時反映。
整個鏈:
contenteditable div(wangEditor 編輯區)
└── DOM 樹(p、span、text node...)
↑
savedRange 指向這裡的某個位置
↑
insertNode(node) 把新 text node 插進去
↑
瀏覽器重新渲染 → 畫面出現新字
wangEditor 本身不知道這件事,所以後面才需要 this.editor.change.emit() 通知它內容變了。
- Ex
// 假設這是在 Vue 組件的方法中,且已經獲取了 editor 實例
insertTextDirectly(text) {
const editor = this.editor; // wangEditor 實例
const range = editor.selection.getRange(); // 取得目前的 Range 物件 (savedRange)
if (!range) return;
// 1. 建立一個純文字節點 (Text Node)
const textNode = document.createTextNode(text);
// 2. 直接操作 DOM:將節點插入到 Range 指向的位置
// 這一步會讓瀏覽器立即渲染出新文字,但 editor 內部的 html/json 狀態尚未更新
range.insertNode(textNode);
// 3. 移動光標到新插入節點的後面,避免連續輸入時位置錯誤
range.collapse(false);
// 4. 手動觸發變更通知
// 讓 wangEditor 執行內部的同步邏輯(例如更新 editor.txt.html() 的回傳值)
// 並觸發選單高亮狀態檢查等後續動作
editor.change.emit();
}
- collapse(false):
false 參數代表折疊到 End(終點),也就是新插入節點的後方。
這會讓 Range 變成一個「折疊狀態」的游標(即長度為 0 的點),這樣使用者接下來打字時,字才會順著新節點後面出現。
圖解邏輯
假設編輯器原本內容是 |(游標位置):
insertNode("A"):
內容變為 [A](Range 現在包裹著 A)。
collapse(false):
內容變為 A|(Range 折疊到 A 的後方,準備接受下一個輸入)。
搭配 wangEditor 的完整操作
在 Vibe Coding 流程中,為了確保 UI 狀態同步(例如 iView 組件的響應式顯示),通常會這樣寫:
JavaScript
// 插入節點
range.insertNode(textNode);
// 1. 將 Range 本身折疊到節點後方
range.collapse(false);
// 2. 核心步驟:必須把這個 Range 對象重新同步回瀏覽器的 Selection
const selection = window.getSelection();
selection.removeAllRanges(); // 清除舊選區
selection.addRange(range); // 放入折疊後的新選區,游標就會閃爍在正確位置
// 3. 通知 wangEditor 更新內部狀態
this.editor.change.emit();
這樣處理後,你在 Windsurf 中開發的自定義功能(如:自動補全、快捷插入變數等)就能擁有跟原生輸入一樣流暢的體驗,不會發生「字插進去了,游標卻跑回行首」的 Bug。