式文本選區(qū)追蹤組合式函數(shù))
前端【免費(fèi)下載鏈接】vueuseCollection of essential Vue Composition Utilities for Vue 3項(xiàng)目地址https://gitcode.com/gh_mirrors/vu/vueuse點(diǎn)擊查看免費(fèi)下載導(dǎo)讀useTextSelection是 VueUsevueuse/core中歸屬于Sensors傳感器分類的一個(gè)組合式函數(shù)它基于瀏覽器原生的Window.getSelectionAPI將用戶選中了哪些文本、選區(qū)覆蓋哪些范圍、選區(qū)對(duì)應(yīng)的矩形區(qū)域這類信息封裝為 Vue 響應(yīng)式狀態(tài)。讀完本文你將掌握useTextSelection的完整 API、源碼級(jí)實(shí)現(xiàn)原理以及如何用它快速構(gòu)建選中文本高亮、復(fù)制引導(dǎo)、標(biāo)注批注等交互功能??焖偕鲜肿钚】捎檬纠?Vue 3 的script setup中直接調(diào)用即可無需任何初始化配置script setup langts import { useTextSelection } from vueuse/core const state useTextSelection() /script template p{{ state.text }}/p /template當(dāng)用戶在頁面上框選任意文本時(shí)state.text會(huì)立刻變?yōu)楸贿x中的字符串清除選區(qū)后state.text會(huì)自動(dòng)恢復(fù)為空字符串。整個(gè)過程不需要手動(dòng)監(jiān)聽事件也不需要手動(dòng)調(diào)用清理邏輯。useTextSelection已從 packages/core/index.ts 統(tǒng)一導(dǎo)出因此既可以通過import { useTextSelection } from vueuse/core引入也可以直接從vueuse/core/useTextSelection子路徑引入。vueuse/core要求vue為^3.5.0的 peer 依賴請(qǐng)確保項(xiàng)目基于 Vue 3 使用參見 packages/core/package.json。返回值四個(gè)響應(yīng)式字段useTextSelection的返回類型定義在 packages/core/useTextSelection/index.ts 中共四個(gè)字段字段類型含義textComputedRefstring當(dāng)前選中的純文本內(nèi)容無選區(qū)時(shí)為rectsComputedRefDOMRect[]選區(qū)中每個(gè) Range 對(duì)應(yīng)的視口矩形getBoundingClientRect()數(shù)組rangesComputedRefRange[]選區(qū)包含的 Range 對(duì)象數(shù)組selectionShallowRefSelection \| null底層的Selection單例對(duì)象本身text是最常用的字段直接對(duì)應(yīng)selection.toString()ranges允許你進(jìn)一步操作選區(qū)結(jié)構(gòu)例如遍歷Range做自定義標(biāo)記rects基于ranges派生每個(gè)Range經(jīng)range.getBoundingClientRect()得到其矩形位置可用于給被選中文字繪制高亮浮層或定位工具條selection是底層Selection單例的淺引用shallow ref適合需要直接調(diào)用SelectionAPI如anchorNode、focusNode、collapse()的場景。真實(shí)示例實(shí)時(shí)展示選中文本與選區(qū)矩形倉庫自帶的 packages/core/useTextSelection/demo.vue 演示了text與rects的組合用法script setup langts import { useTextSelection } from vueuse/core import { computed } from vue const { rects, text } useTextSelection() const selectedStyle computed(() text.value ? text-primary : text-gray-400) /script template div p classfont-600 text-blue-600 You can select any text on the page. /p p strongSelected Text:/strong em :classselectedStyle classwhitespace-pre h-44 overflow-y-auto block {{ text || No selected }}/em /p p strongSelected rects:/strong pre classh-72 langjson{{ rects }}/pre /p /div /template從 demo 中可以提煉兩個(gè)實(shí)戰(zhàn)要點(diǎn)無選區(qū)狀態(tài)的 UI 兜底text || No selected在空字符串時(shí)展示占位文案避免界面出現(xiàn)空白rects直接可序列化DOMRect對(duì)象包含x、y、width、height、top、right、bottom、left等屬性用pre langjson打印即可直觀查看選區(qū)在頁面中的精確位置這也是實(shí)現(xiàn)選中即彈出高亮/標(biāo)注工具的數(shù)據(jù)基礎(chǔ)。源碼級(jí)原理事件驅(qū)動(dòng) 派生計(jì)算整個(gè)實(shí)現(xiàn)非常精簡核心邏輯全部位于 packages/core/useTextSelection/index.tsexport function useTextSelection(options: UseTextSelectionOptions {}): UseTextSelectionReturn { const { window defaultWindow, } options const selection shallowRefSelection | null(window?.getSelection() ?? null) const text computed(() selection.value?.toString() ?? ) const ranges computedRange[](() selection.value ? getRangesFromSelection(selection.value) : []) const rects computed(() ranges.value.map(range range.getBoundingClientRect())) function onSelectionChange() { selection.value null // trigger computed update if (window) selection.value window.getSelection() } if (window) useEventListener(window.document, selectionchange, onSelectionChange, { passive: true }) return { text, rects, ranges, selection, } }1. 初始化直接讀取當(dāng)前選區(qū)調(diào)用時(shí)通過window?.getSelection()獲取瀏覽器當(dāng)前存在的Selection單例存入shallowRef。因此即使組件掛載時(shí)用戶已經(jīng)選中了文本text也能立即拿到既有選區(qū)內(nèi)容——這一點(diǎn)在測(cè)試should initialize with an existing range中得到了驗(yàn)證見 packages/core/useTextSelection/index.browser.test.ts。2. 事件驅(qū)動(dòng)監(jiān)聽selectionchange瀏覽器沒有為選區(qū)變化提供可訂閱的流式 API因此組件通過useEventListener在window.document上注冊(cè)selectionchange事件監(jiān)聽使用{ passive: true }以優(yōu)化滾動(dòng)場景下的性能。useEventListener負(fù)責(zé)在組件卸載時(shí)自動(dòng)移除監(jiān)聽無需手動(dòng)清理其注冊(cè)/清理邏輯參見 packages/core/useEventListener/index.ts。監(jiān)聽回調(diào)onSelectionChange中有一段精妙的實(shí)現(xiàn)function onSelectionChange() { selection.value null // trigger computed update if (window) selection.value window.getSelection() }先置null再賦新值是因?yàn)镾election在瀏覽器中是單例對(duì)象——選區(qū)變化時(shí)對(duì)象引用本身不變只是內(nèi)部狀態(tài)變了。若直接重新賦值shallowRef會(huì)認(rèn)為引用未變化而跳過觸發(fā)導(dǎo)致text/rects不更新。顯式先賦null再賦新值即可強(qiáng)制刷新派生 computed。測(cè)試selection should always return the singleton Selection object no matter how the selection changes正是對(duì)這一行為的約束無論選區(qū)如何變化selection.value始終指向同一個(gè)Selection單例見 index.browser.test.ts。3. 派生計(jì)算text / ranges / rectstextselection.value?.toString() ?? 直接取選區(qū)文本ranges通過getRangesFromSelection按selection.rangeCount逐項(xiàng)調(diào)用selection.getRangeAt(i)收集所有 Range見 index.tsrects對(duì)ranges逐一映射range.getBoundingClientRect()得到以視口為坐標(biāo)系的矩形數(shù)組。三者均為computed僅當(dāng)selection引用變化即選區(qū)事件發(fā)生時(shí)才重新求值派生成本極低。配置選項(xiàng)ConfigurableWindowuseTextSelection接受一個(gè)可選的options對(duì)象其類型UseTextSelectionOptions繼承了 VueUse 通用的ConfigurableWindow接口export interface ConfigurableWindow { /** * Specify a custom window instance, e.g. working with iframes or in testing environments. */ window?: Window }該接口定義于 packages/core/_configurable.ts核心作用是在iframe 環(huán)境或測(cè)試環(huán)境中注入自定義window實(shí)例使選區(qū)追蹤作用于目標(biāo)文檔而非全局窗口。未傳入時(shí)默認(rèn)值取自export const defaultWindow isClient ? window : undefined見 packages/core/_configurable.ts——在 SSR/非瀏覽器環(huán)境下為undefined此時(shí)useTextSelection內(nèi)部會(huì)跳過getSelection()調(diào)用與事件注冊(cè)返回的text為、ranges/rects為空數(shù)組保證服務(wù)端渲染不會(huì)報(bào)錯(cuò)。典型用法iframe 場景const { text, rects } useTextSelection({ window: iframe.contentWindow, })測(cè)試驗(yàn)證與行為契約packages/core/useTextSelection/index.browser.test.ts 通過 Vitest happy-dom 定義了該函數(shù)的四個(gè)核心行為契約可作為你理解與使用時(shí)的權(quán)威參考選區(qū)對(duì)象單例性無論選區(qū)怎么變化selection.value始終指向同一個(gè)Selection對(duì)象初始空選區(qū)頁面無選區(qū)時(shí)text為rects、ranges均為空數(shù)組anchorNode/focusNode為null初始化時(shí)讀取既有選區(qū)調(diào)用前已存在選區(qū)則text直接反映該選區(qū)內(nèi)容ranges/rects長度均為 1selectionchange驅(qū)動(dòng)的實(shí)時(shí)更新模擬選中Hello World節(jié)點(diǎn)并派發(fā)selectionchange事件后text變?yōu)镠ello WorldremoveAllRanges()后再派發(fā)事件所有派生值恢復(fù)為空。測(cè)試中手動(dòng)派發(fā)new Event(selectionchange)的方式也印證了該函數(shù)的更新完全依賴selectionchange事件這一事實(shí)——這也是在測(cè)試代碼中觸發(fā)其更新的標(biāo)準(zhǔn)手段。典型應(yīng)用場景選中文本高亮標(biāo)注用rects計(jì)算選中區(qū)域的精確位置疊加高亮浮層或批注工具條復(fù)制引導(dǎo) / 詞典釋義實(shí)時(shí)監(jiān)聽text在用戶選中詞句時(shí)彈出復(fù)制翻譯查詞按鈕選區(qū)統(tǒng)計(jì)與分享在閱讀類應(yīng)用中統(tǒng)計(jì)用戶選中文本或生成可分享的引用片段富文本選區(qū)操作配合ranges對(duì)選區(qū) Range 做包裹標(biāo)簽、插入標(biāo)記等 DOM 操作。小結(jié)useTextSelection以約 20 行核心代碼將瀏覽器底層的Selection單例模型與 Vue 響應(yīng)式系統(tǒng)優(yōu)雅地銜接起來shallowRef承載Selectionselectionchange事件驅(qū)動(dòng)刷新computed派生text、ranges、rects三路只讀狀態(tài)。它無需任何配置即可開箱即用同時(shí)通過ConfigurableWindow保留了 iframe 與 SSR 場景的擴(kuò)展能力是 Vue 3 中處理用戶文本選擇這一交互需求的輕量而完備的解決方案。贊分享前端【免費(fèi)下載鏈接】vueuseCollection of essential Vue Composition Utilities for Vue 3項(xiàng)目地址https://gitcode.com/gh_mirrors/vu/vueuse點(diǎn)擊查看免費(fèi)下載相關(guān)推薦airi 項(xiàng)目實(shí)戰(zhàn)用 VueUse useTextSelection 在 Vue 3 中響應(yīng)式追蹤用戶文本選區(qū)airi 項(xiàng)目實(shí)戰(zhàn)用 VueUse useTextSelection 在 Vue 3 中響應(yīng)式追蹤用戶文本選區(qū) 導(dǎo)讀 useTextSelection 是 VAI 應(yīng)用人工智能大模型數(shù)字人AI Agent語音前端后端桌面應(yīng)用移動(dòng)開發(fā)即時(shí)通訊3D渲染AIRI 項(xiàng)目中的 usePreferredColorScheme響應(yīng)式追蹤 prefers-color-scheme 的 VueUse 組合式函數(shù)實(shí)戰(zhàn)指南AIRI 項(xiàng)目中的 usePreferredColorScheme響應(yīng)式追蹤 prefers color scheme 的 VueUse 組合式函數(shù)實(shí)戰(zhàn)指南AI 應(yīng)用人工智能大模型數(shù)字人AI Agent語音前端后端桌面應(yīng)用移動(dòng)開發(fā)即時(shí)通訊3D渲染VueUse vueuse/math useMin響應(yīng)式 Math.min 組合式函數(shù)完全指南VueUse vueuse/math useMin響應(yīng)式 Math.min 組合式函數(shù)完全指南 useMin 是 VueUse vueuse/math 擴(kuò)前端上一篇comprehensive-rust 課程精講用所有權(quán)與借用檢查器實(shí)現(xiàn) Single-Use Values一次性值下一篇Web-Dev-For-Beginners 實(shí)戰(zhàn)作業(yè)解析用 JavaScript 條件邏輯實(shí)現(xiàn)學(xué)生成績判定創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考