1.方案背景
产品提了个选中文字弹出定制化菜单的需求(要覆盖浏览器默认的菜单),弹出菜单位置要合适,不覆盖选中文本,方便点击
2.技术方案
PC和Android h5 利用contextmenu事件,preventDefault阻止默认菜单,window.getSelection() 获取选择的文本和选择的文本范围
3.表现方式
不会挡住选中文字,默认在选中文本顶部以及中间
PC
H5
4.开发难点
(1)定位:如何把菜单定位到 已选中文本 合适的位置,并且不受滚动等其他样式干扰。
5.内部业务处理
(一)获取选中文本的内容和位置 window.getSelection() 返回一个Selection对象,表示用户选择的文本范围或光标的当前位置。
选中文本内容:window.getSelection().toString().trim()
选中文本范围 其中有3个概念
锚点(anchor) 选区的起始点
焦点(focus) 该选区的终点
范围(range)文档中连续的一部分。一个范围包括整个节点,也可以包含节点的一部分
比如下图就包括了3个节点 2个p和文本节点
而这个范围信息 会作为range对象返回 (除在selection获取外平时可通过document.createRange创建或者new Range,后续如果有不太好处理的这种定位的 都可以去了解下range)
现在我们先去获取选中文本的“范围对象”
window.getSelection().getRangeAt(0) --》getRangeAt(index) 获取选中某个选中范围的的range 因为我们这直选中一个范围就传0
获取选中文本范围对象位置
利用getBoundingClientRect (支持dom和range对象)获取边界矩形 (最左到最右 最上到最下组合的矩形)
返回元素的大小及其相对于视口的位置
类型一 选中文本在中间
类型二 选中文本整行 (看矩形最左侧和最右侧)
left 就是0
现在我们就可以实现我们的目标了 选中文本顶部以及中间
现在获取的x 和 y 是针对视口的 所以得把我们的菜单传到视口层 利用 Teleport -- 传到body 这样absolute的就是针对整个视口了
因为我们菜单也有宽高 所以想要居中就需要进行对应的计算 针对菜单宽高计算如下