Open Genzhen opened 4 years ago
每日一题会在下午四点在交流群集中讨论,五点 Github、交流群同步更新答案
当对Dom元素进行一系列操作时,对Dom进行访问和修改Dom引起的重绘和重排都比较消耗性能,所以关于操作Dom,应该从以下几点出发:
首先不管在什么场景下。操作Dom一般首先会去访问Dom,尤其是像循环遍历这种时间复杂度可能会比较高的操作。那么可以在循环之前就将主节点,不必循环的Dom节点先获取到,那么在循环里就可以直接引用,而不必去重新查询。
let rootElem = document.querySelector('#app');
let childList = rootElem.child; // 假设全是dom节点
for(let i = 0;i<childList.len;j++){
/**
* 根据条件对应操作
*/
}
利用document.createDocumentFragment()
方法创建文档碎片节点,创建的是一个虚拟的节点对象。向这个节点添加dom节点,修改dom节点并不会影响到真实的dom结构。
我们可以利用这一点先将我们需要修改的dom一并修改完,保存至文档碎片中,然后用文档碎片一次性的替换真是的dom节点。与虚拟dom类似,同样达到了不频繁修改dom而导致的重排跟重绘的过程。
let fragment = document.createDocumentFragment();
const operationDomHandle = (fragment) =>{
// 操作
}
operationDomHandle(fragment);
// 然后最后再替换
rootElem.replaceChild(fragment,oldDom);
这样就只会触发一次回流,效率会得到很大的提升。如果需要对元素进行复杂的操作(删减、添加子节点),那么我们应当先将元素从页面中移除,然后再对其进行操作,或者将其复制一个(cloneNode()),在内存中进行操作后再替换原来的节点。
var clone=old.cloneNode(true);
operationDomHandle(clone);
rootElem.replaceChild(clone,oldDom)
批量读,一次性写。先对一个不在render tree上的节点进行操作,再把这个节点添加回render tree。这样只会触发一次DOM操作。 使用requestAnimationFrame()
,把任何导致重绘的操作放入requestAnimationFrame
js模拟DOM树并对DOM树操作的一种技术。virtual DOM是一个纯js对象(字符串对象),所以对他操作会高效。
利用virtual dom,将dom抽象为虚拟dom,在dom发生变化的时候先对虚拟dom进行操作,通过dom diff算法将虚拟dom和原虚拟dom的结构做对比,最终批量的去修改真实的dom结构,尽可能的避免了频繁修改dom而导致的频繁的重排和重绘。