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)  ← 查詢注音
    ↓
顯示候選浮層