在开发项目的时候,有一个需求是,给表格的每一行添加一个右键菜单,在实现的过程中发现点击右键之后,菜单出现的位置并不在鼠标点击的位置,而是发生了偏移
Right-click inside this box to open the menu.
组件排查
dom结构大概是这样的,外层父组件包裹了内层的子组件,子组件里面使用了menu
<div class="container">
<div class="transformed-parent">
Right-click inside this box to open the menu.
<div class="menu" id="context-menu">
<div class="menu-item">Option 1</div>
<div class="menu-item">Option 2</div>
<div class="menu-item">Option 3</div>
</div>
</div>
</div>看上去没有什么问题,在接着排查样式的时候,发现了父组件的样式里面增加了transform,而这个菜单组件的定位看了一眼源码之后,恰好使用的fixed,这下就找到问题的原因了。
理论知识
- transform会影响坐标系,会构建一个新的坐标系
- clientX和clientY返回的是视口的坐标,也就是说相对于浏览器左上角的坐标
- 在使用fixed定位后,由于父组件使用了transform,导致定位的参考会改为父组件而不是视口
真相只有一个
右键点击捕获的坐标是相对于视口的,但是呈现的位置是相对于父组件的,也就是说原点位置变了
解决办法
- 最简单的方式是在不影响原有功能的基础上去掉transform
- 将菜单的定位从fixed改为absolute,但是我这个需求用的第三方组件,所以pass
- 移动菜单的位置,不要放在父组件里面,这种方式需要看具体情况,如果是父组件是首页那种,包裹了很多子组件组成了首页,就不太好操作。
<div class="container">
<div class="transformed-parent">
Right-click inside this box to open the menu.
</div>
</div>
<!-- 将菜单放在容器外部 -->
<div class="menu" id="context-menu">
<div class="menu-item">Option 1</div>
<div class="menu-item">Option 2</div>
<div class="menu-item">Option 3</div>
</div>