此前对于这个这种问题基本没有了解,碰到问题都是网上搜索找点代码来用,对于 window.getSelection() 和 document.createRange() 这两个 API 可以说是很眼熟了,但是仅仅停留在眼熟上。最近又碰到了这个问题,所以啊,一切欠的账都是需要还的。
找点代码解决问题之后,再次尝试找找有没有相关的 npm 包可用,未果,索性自己折腾一个。借此深入一下对于 Selection 的理解,顺便又能发挥下自己写的 npm 包仓库模板的作用了,一举两得。
话不多说,直接先发个包再说:
这里重点介绍三个工具函数:
createSelectionChangeListener()
该函数根据命令可知,是用于创建 Selection 改变的监听器的,内部处理输入类节点和展示类节点的区别,方便用户直接处理指定节点 Selection 变化的回调。
值得注意的是在此之前我还在想怎么监听光标变化,目前来看只能通过 document.addEventListener('selectionchange', handler) 的方式监听。
createCacheSelectionListener()
这其实就是基于 createSelectionChangeListener 创建的工具函数,本来之前还根据输入类组件单独实现的在 blur 事件才缓存的,这会导致实现起来有些麻烦,直接全部都用 createSelectionChangeListener 最省事,写好回调做好缓存就好了。这个函数会返回 disposer 和 restorer 分别用于移除监听事件和恢复当前监听节点的 Selection 状态。
selectNode()
这个函数可以用于选择任何可见的 DOM 节点,当前支持 HTMLElement 和 Text 两大类。默认情况下只需要传入指定的节点即可,内部会处理为合适的选择方式:
- 如果传入节点是输入类节点,会默认 focus 到末尾,可自行定制选择范围
- 如果是其他 HTMLElement 或者 Text 节点,会再判断元素是否在 contenteditable 节点中:
- 如果在,则默认 focus 到末尾,可自行定制选择范围
- 如果不在,因为此时节点不能 focus,则默认使用选择整个节点的方式代替,可自行定制选择范围
感兴趣的朋友可以直接在控制台执行如下代码看看效果:
async function getSelectNode() {
const modules = await import('https://unpkg.com/selection-extra/dist/index.mjs')
const { selectNode } = modules;
return selectNode
}
const selectNode = await getSelectNode()
selectNode(document.querySelector('h1'))
更丰富的演示猛戳这里。
总结
发现了可以自由控制光标和选择内容之后还蛮好玩的,不过不懂为啥没有现成的工具包,目前实现的也没考虑太多兼容性,不过都 2023 年了,兼容性应该问题不大了吧 😂 之后会再基于这个实现封装个 React Hook 的包,Vue 不知道没啥基础好不好写 Composition API,有机会可以试试。