选中文本自定义右键菜单,菜单位置跟着选中文本走

380 阅读2分钟

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的就是针对整个视口了

因为我们菜单也有宽高 所以想要居中就需要进行对应的计算 针对菜单宽高计算如下