国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

選中鼠標附近的文字

shuibo / 655人閱讀

摘要:它的原理是深度優先遞歸遍歷這個元素以及其子元素,通過不斷試探選中區域,并與鼠標座標對比來定位確切位置。原理現在總結一下原理通過獲得鼠標所指最接近的元素以及文本位置。驗證鼠標此時在單詞區域范圍中。

最近終于抽空給 Saladict 實現了鼠標懸浮取詞功能,使用了較為簡潔的實現方式,這里分享一下原理以及坑的處理。

初嘗試

這個需求其實很早就被人提 issue 了,當時做了一番搜索,最后嘗試了 document.caretPositionFromPoint / document.caretRangeFromPoint ,效果不太理想。

如果看 mdn 給的例子,就會發現,它是遍歷每個元素添加事件的。這么做的原因是當使用這個方法的時候,如果鼠標指向元素空白的地方,它會就近取位置。所以例子通過給粒度更細的元素綁定來避免這個問題。然而實際上這么做還是不足夠的,一個段落末行也許只有幾個字符,這時空出接近一行,也會有上面的問題。

所以當時就擱置了這個功能。

靈感

直到最近,看到一個同類的開源劃詞翻譯擴展 FairyDict 實現了取詞功能,遍觀摩了一番源碼。

它的原理是深度優先遞歸遍歷這個元素以及其子元素,通過不斷試探選中區域,并與鼠標座標對比來定位確切位置。

有沒有發現問題,這個遍歷過程不正是上面 document.caretPositionFromPoint 干的事么,那么我們只需要最后量一下鼠標是否在取詞范圍中即可。

原理

現在總結一下原理:

通過 document.caretPositionFromPoint 獲得鼠標所指最接近的元素以及文本位置 offset。

找出 offset 最接近的單詞。

通過 Range 獲得部分文本(單詞)的尺寸和座標。

驗證鼠標此時在單詞區域范圍中。

選中這個單詞。Selection 支持直接添加 Range

實現

按原理來實現就很簡單了。本文上按 alt 可體驗取詞效果。

/**
 * @param {MouseEvent} e
 * @returns {void}
 */
function selectCursorWord (e) {
  const x = e.clientX
  const y = e.clientY

  let offsetNode
  let offset

  const sel = window.getSelection()
  sel.removeAllRanges()

  if (document["caretPositionFromPoint"]) {
    const pos = document["caretPositionFromPoint"](x, y)
    if (!pos) { return }
    offsetNode = pos.offsetNode
    offset = pos.offset
  } else if (document["caretRangeFromPoint"]) {
    const pos = document["caretRangeFromPoint"](x, y)
    if (!pos) { return }
    offsetNode = pos.startContainer
    offset = pos.startOffset
  } else {
    return
  }

  if (offsetNode.nodeType === Node.TEXT_NODE) {
    const textNode = offsetNode
    const content = textNode.data
    const head = (content.slice(0, offset).match(/[-_a-z]+$/i) || [""])[0]
    const tail = (content.slice(offset).match(/^([-_a-z]+|[u4e00-u9fa5])/i) || [""])[0]
    if (head.length <= 0 && tail.length <= 0) {
      return
    }

    const range = document.createRange()
    range.setStart(textNode, offset - head.length)
    range.setEnd(textNode, offset + tail.length)
    const rangeRect = range.getBoundingClientRect()

    if (rangeRect.left <= x &&
        rangeRect.right >= x &&
        rangeRect.top <= y &&
        rangeRect.bottom >= y
    ) {
      sel.addRange(range)
    }

    range.detach()
  }
}
交互

最后,如果要提供功能開關或者設置不同按鍵的話,簡單的處理可以參考 FairyDict 讓事件處理空轉。但對于 mousemove 這類比較頻繁的事件,在關閉的時候取消事件監聽可能更好一些。在 Saladict 中甚至將“面板被釘住”跟“普通情況”分開為不同的模式,這里借助 RxJS 來處理復雜的邏輯,可參考源碼。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/95615.html

相關文章

  • 宇宙最強vscode教程(基礎篇)

    摘要:在命令面板中你可以輸入命令進行搜索中英文都可以,然后執行。命名面板中可以執行各種命令,包括編輯器自帶的功能和插件提供的功能。 本文主要介紹vscode在工作中常用的快捷鍵及插件,目標在于提高工作效率本文的快捷鍵是基于mac的,windows下的快捷鍵放在括號里 Cmd+Shift+P(win Ctrl+Shift+P) [TOC] 零、快速入門 有經驗的可以跳過快速入門或者大致瀏覽一...

    Jason_Geng 評論0 收藏0
  • 原生JS寫一個功能強大編輯器

    摘要:主要采用了原生與調用結合的功能實現功能。所以根據這種方法,讀者可以根據自己的需求添加更多的功能,比如在編輯框里面插入一個可以點擊的標簽或者添加一個代碼塊希望能讀到此文章的讀者,能在下方一起交流,更希望大佬提出錯誤,謝謝地址 因為一個同學,要做一個能加入圖片的留言板功能,類型與QQ空間留言板和百度貼吧發帖的那種形式,同時在網上找了找發生網上對這方面的交流很少,所以發表這篇文章拋磚引玉,希...

    luck 評論0 收藏0
  • 原生JS寫一個功能強大編輯器

    摘要:主要采用了原生與調用結合的功能實現功能。所以根據這種方法,讀者可以根據自己的需求添加更多的功能,比如在編輯框里面插入一個可以點擊的標簽或者添加一個代碼塊希望能讀到此文章的讀者,能在下方一起交流,更希望大佬提出錯誤,謝謝地址 因為一個同學,要做一個能加入圖片的留言板功能,類型與QQ空間留言板和百度貼吧發帖的那種形式,同時在網上找了找發生網上對這方面的交流很少,所以發表這篇文章拋磚引玉,希...

    王晗 評論0 收藏0

發表評論

0條評論

shuibo

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<