划词搜索必须监听 mouseup 事件,配合 window.getselection() 获取选中文本,document 级监听;移动端需处理 touchend 并 preventdefault();取值用 getselection().tostring().trim();清除旧高亮用 replacewith;高亮用 range.surroundcontents,避免 innerhtml。

划词搜索必须监听 mouseup 事件,不是 click
划词搜索的核心是捕获用户松开鼠标那一刻的选中文本,click 事件完全无效——它只在点击时触发,不感知选区。真正该用的是 mouseup,配合 window.getSelection() 获取当前高亮文本。
- 必须在
document级监听,不能只绑在按钮上:用户可能先划词再点按钮,但划词行为本身和按钮无关 - 移动端需额外处理
touchend,且要加preventDefault()防止长按弹出系统菜单干扰选区 -
getSelection().toString().trim()是安全取值方式;直接访问getSelection().anchorNode容易因 DOM 变动报错 - 若页面用了
user-select: none(比如代码块),划词会失败,得临时移除或改用pointer-events: none配合z-index绕过
按钮点击只是触发器,不负责取词
按钮本身不参与划词逻辑,它只做一件事:拿到已存在的选区并执行搜索。所以它的 onclick 处理函数里,第一行就该是 const keyword = window.getSelection().toString().trim()。
- 如果
keyword为空,说明没划词或划了空白,直接return,别弹提示框或发请求 - 不要在按钮上加
disabled或 loading 状态——划词和点击是两个独立动作,禁用按钮反而阻断合法操作 - 按钮文案建议写“搜选中内容”,比“搜索”更明确行为边界,减少用户误点空白处再点按钮的困惑
搜索前必须清理旧高亮,否则 mark 标签会嵌套
连续划词搜索时,若不主动清除上次的 <mark></mark>,新高亮会包在旧 <mark></mark> 里面,导致样式错乱、DOM 节点泄漏,甚至 getSelection() 返回异常节点。
- 推荐用
document.querySelectorAll('mark').forEach(el => el.replaceWith(el.textContent))清理,比innerHTML替换更安全 - 别用
remove(),它会丢掉文本节点父子关系,后续splitText()操作容易报错 - 清理动作必须放在搜索逻辑最开头,哪怕用户划的是空格或换行,也要先清再判
高亮实现要用 Range,别碰 innerHTML
直接改 element.innerHTML 会销毁所有绑定事件、Vue/React 响应式数据、动态插入的节点,真实项目里一搜就崩。
- 正确做法是遍历所有文本节点,对每个匹配位置调用
range.surroundContents(markEl) - 遇到
InvalidStateError(常见于跨标签匹配),说明选区跨越了多个元素,此时降级为只高亮第一个完整文本节点内的匹配 - 移动端 Safari 对
surroundContents支持不稳定,可 fallback 到range.extractContents()+ 插入新mark的组合
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











