封装拖拽组件的一些技术要点记录

175 阅读3分钟

工作实践中封装过一个拖拽组件,仅以此文记录过程中碰到的一些问题、及思考角度,其中包含性能优化等知识点。

1. 事件选择?

答:Pointer events,优先drag event,是一类可以为定点设备所触发的DOM事件,被用来创建一个可以有效掌握各类输入设备(鼠标、触控笔和单点或多点的手指触摸)的统一的DOM事件模型。

2. 通过改变position还是translate做位移?

答:为了性能考虑,选择通过translate改变位移较好。

因为改变 position 是会导致浏览器进行重排,浏览器会重新计算受到影响的元素的几何位置。

而使用translate并且开启了3d硬件加速的时候(translate3d),就会强迫浏览器会为这个元素单独开启一个Layer,这个Layer是和原有页面的Layer隔离的,并且不会影响其他元素,所以就不会有重排,这种位置计算是很高效的。

参考文章:

3. 使用translate做位移时层级怎么办?

答:transform可以通过它的translateZ() 来改变元素的层叠顺序,值越大则层级越高。不过通过transform:translateZ() 改变元素z轴层级,必须在其父元素中设置transform-style:preserver-3d 或者在transform中设置perspective() 才有效。

参考文章:

4. 在组件A中引入封装的拖拽组件Draggable,但是希望被拖拽的组件的B的父组件是组件C,怎么办?

答:使用React.Portals,它提供了一种将子节点渲染到存在于父组件以外的DOM节点的优秀的方案。

5. 在4的基础上,希望父组件为C,且拖拽范围不是C的整体范围,只是其中的小部分范围?

答:父组件C提供可选参数limitedScope,限制拖拽范围。

6. 父组件C、被拖拽的组件B后期的大小会改变怎么办?

答:可通过ResizeObserver监视dom元素边界尺寸的变化。

7. onpointermove,用防抖(debounce)还是requestAnimationFrame哪个好?

答:requestAnimationFrame更适合,它不需要传入时间参数,是跟着浏览器的绘制频率自动调节的,可以防止动画失帧。但不兼容 IE9及以下浏览器。

8. 鼠标指针移动到window边界外,能正常拖动吗?

答:使用Element.setPointerCapture(),即使指针移动到window边界之外,也可以正常拖动

9. 怎么实现下图中的动态效果?

GIF 2022-12-16 14-28-43.gif

答:监听onpointermove事件的函数中不限制拖拽范围,监听到onpointerup事件后,判断是否超出边界(绿框),超出则立马设置组件B的位置最远处在边界上,不超出,即会出现图中的“回弹”效果。