Js 拖动的原理?,如何最小化重绘(repaint)和回流(reflow)

166 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

1. js 的拖拽效果主要用到以下三个事件:

mousedown 鼠标按下事件

mousemove 鼠标移动事件

mouseup 鼠标抬起事件

当点击 dom 的时候,记录当前鼠标的坐标值,也就是 x、y 值,以及被拖拽的 dom 的

top、left 值,而且还要在鼠标按下的回调函数里添加鼠标移动的事件:

document.addEventListener("mousemove", moving, false)

和添加鼠标抬起的事件

document.addEventListener("mouseup",function() {

document.removeEventListener("mousemove", moving, false);}, false);

这个抬起的事件是为了解除鼠标移动的监听,因为只有在鼠标按下才可以拖拽,抬起

就停止不会移动了。

当鼠标按下鼠标移动的时候,记录移动中的 x、y 值,那么这个被拖拽的 dom 的 top 和

left 值就是:

top=鼠标按下时记录的 dom 的 top 值+(移动中的 y 值 - 鼠标按下时的 y 值)

left=鼠标按下时记录的 dom 的 left 值+(移动中的 x 值 - 鼠标按下时的 x 值);

image.png

2.如何最小化重绘(repaint)和回流(reflow)

什么是重绘 Repaint 和重排

(回流 reflow)

重绘:当元素的一部分属性发生改变,如外观、背景、颜色等不会引起布局变化,只需要浏览器

根据元素的新属性重新绘制,使元素呈现新的外观叫做重绘。

重排(回流):当 render 树中的一部分或者全部因为大小边距等问题发生改变而需要 DOM 树重

新计算的过程

重绘不一定需要重排(比如颜色的改变),重排必然导致重绘(比如改变网页位置)

方法:

1、需要要对元素进行复杂的操作时,可以先隐藏(display:"none"),操作完成后再显示

2、需要创建多个 DOM 节点时,使用 DocumentFragment 创建完后一次性的加入 document

缓存 Layout 属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回

3、尽量避免用 table 布局(table 元素一旦触发回流就会导致 table 里所有的其它元素回流)

4、避免使用 css 表达式(expression),因为每次调用都会重新计算值(包括加载页面)

5、尽量使用 css 属性简写,如:用 border 代替 border-width, border-style, border-color

6、批量修改元素样式:elem.className 和 elem.style.cssText 代替 elem.style.xxx