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

資訊專欄INFORMATION COLUMN

選中鼠標(biāo)附近的文字

shuibo / 644人閱讀

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

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

初嘗試

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

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

所以當(dāng)時就擱置了這個功能。

靈感

直到最近,看到一個同類的開源劃詞翻譯擴(kuò)展 FairyDict 實(shí)現(xiàn)了取詞功能,遍觀摩了一番源碼。

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

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

原理

現(xiàn)在總結(jié)一下原理:

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

找出 offset 最接近的單詞。

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

驗(yàn)證鼠標(biāo)此時在單詞區(qū)域范圍中。

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

實(shí)現(xiàn)

按原理來實(shí)現(xiàn)就很簡單了。本文上按 alt 可體驗(yàn)取詞效果。

/**
 * @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()
  }
}
交互

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

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/95615.html

相關(guān)文章

  • 宇宙最強(qiáng)vscode教程(基礎(chǔ)篇)

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

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

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

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

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

    王晗 評論0 收藏0

發(fā)表評論

0條評論

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