wangEditor取得選取內容 - daniel-qa/Vue GitHub Wiki
抓取 IVS 碼
使用者選取「少﹢IVS」
↓
主碼 → 查注音 / 選字
↓
使用者選了第幾個字(index)
↓
把原本的「少﹢IVS」整串插回去
所以只需要:
async autoGetSelectedText() {
const selectText = this.editor.selection.getSelectionText()
if (!selectText) return
// 過濾 IVS,只留主碼查注音
const ivsPattern = /[\u{E0100}-\u{E01EF}]/gu
const baseChar = selectText.replace(ivsPattern, '')
this.selectedText = baseChar // 拿去查注音
this.selectedRawText = selectText // 原始字串(含 IVS)保留備用
// 使用者選字後,直接把 selectText 原串插回去即可
}
IVS(Ideographic Variation Sequence)取出說明
| 項目 | 說明 |
|---|---|
| 正則表達式 | /[\u{E0100}-\u{E01EF}]/gu |
[ ] |
字元集合(character class),匹配其中任一字元 |
\u{E0100} |
Unicode code point(ES6+ 寫法),IVS 起始範圍 |
\u{E01EF} |
Unicode code point,IVS 結束範圍 |
- |
範圍運算,表示從起始到結束的所有碼位 |
g flag |
global,匹配所有結果(不只第一個) |
u flag |
Unicode 模式,必要,否則無法解析 \u{...} |
無 u flag 風險 |
無法正確匹配超出 BMP(U+FFFF 以上)的字元,甚至會報錯 |
| 適用範圍 | Unicode Variation Selectors Supplement(IVS 範圍) |
如何捕捉選取事件並處理
- 真正偵測選取的地方
editorElem.addEventListener('mouseup', handleSelection)
editorElem.addEventListener('keyup', handleSelection)
綁在編輯器容器上的 mouseup / keyup,用戶拖曳選取文字放開滑鼠或用鍵盤 Shift 選取時觸發。
因為有兩種選取方式,需要分別偵測:
1 .mouseup — 滑鼠拖曳選取
用戶用滑鼠拖曳選取文字,放開滑鼠的瞬間選取才完成。
所以要監聽 mouseup(放開),而不是 mousedown(按下)。
若監聽 mousedown:選取尚未完成,getSelectionText() 取到的是空的或舊的內容。
2 .keyup — 鍵盤選取
用戶用 Shift + ←/→/↑/↓ 或 Shift + End/Home 鍵盤選取文字,同樣是放開按鍵的瞬間選取才完成。
所以要監聽 keyup。
若監聽 keydown:同樣問題,選取還在進行中。
為什麼綁在 editorElem(容器 div)而非 document
addSelectionListener() {
// 監聽 mouseup 和 keyup 事件來偵測選取
// 防呆
const editorElem = this.$refs.editor
if (!editorElem) return
const handleSelection = () => {
// 延遲執行 100ms,確保選取完成
setTimeout(() => {
// 注音模式下才執行
if (!this.editor || !this.editor.isZhuyinFont) return
// 檢查是否有選取文字
const isSelectEmpty = this.editor.selection.isSelectionEmpty()
if (!isSelectEmpty) {
// 取得選取字
this.autoGetSelectedText()
}
}, 100)
}
editorElem.addEventListener('mouseup', handleSelection) // 偵測 mouse 放開
editorElem.addEventListener('keyup', handleSelection) // 偵測 keyboard 放開
},
縮小範圍:只有在編輯器內的操作才觸發,避免頁面其他地方的 mouseup/keyup 也進來 內部 contenteditable 的事件會冒泡到容器 div,所以可以在這裡統一攔截
- 1 .在 mounted 的,在 initEditor,綁定
mounted() {
this.initEditor()
this._closeOnOutsideClick = (e) => {
if (!this.popoverVisible) return
const popover = this.$el.querySelector('.phonic-popover')
if (popover && !popover.contains(e.target)) {
this.closePopover()
}
}
document.addEventListener('mousedown', this._closeOnOutsideClick)
},
initEditor()
initEditor() {
const editor = new E(this.$refs.editor)
editor.config.onchange = (html) => {
this.content = html
}
editor.config.uploadImgShowBase64 = true
this.$editorTools.initMyEditor(editor, this)
editor.create()
this.editor = editor
// 監聽選取事件(注音模式下自動取得第一個字)
this.addSelectionListener()
},
initEditor() {
// 建立 wangEditor 編輯器實例,綁定至 DOM ref
const editor = new E(this.$refs.editor)
// 監聽內容變更,同步更新 content 資料
editor.config.onchange = (html) => {
this.content = html
}
// 啟用圖片以 Base64 格式上傳(不需後端接口)
editor.config.uploadImgShowBase64 = true
// 套用自訂編輯器工具設定(toolbar、選單等)
this.$editorTools.initMyEditor(editor, this)
// 初始化並掛載編輯器至 DOM
editor.create()
// 將編輯器實例存入 data,供其他方法存取
this.editor = editor
// 註冊文字選取事件監聽(注音模式下自動擷取第一個字)
this.addSelectionListener()
},
用戶操作(拖曳/Shift+方向鍵)
↓
mouseup / keyup 事件觸發
↓
setTimeout 50ms 延遲
↓
檢查 isZhuyinMode && !isSelectionEmpty
↓
editor.selection.getSelectionText() ← 這裡取得選取文字
↓
取得第一個字元 & Unicode
↓
await lookupPhonic(firstChar) ← 查詢注音
↓
顯示候選浮層