DOM操作会导致浏览器重解析,引起重排(回流)和重绘,直接影响页面性能

对DOM的操作一般有两种:修改已存在页面上的DOM元素(更改样式),创建插入新的DOM元素

这里提出几个方案来减少DOM操作次数,减少重排和重绘的频率

修改DOM元素的样式


1、给DOM元素直接添加一个新的css类名

适合修改一个DOM元素的样式。给一个DOM元素一次性添加多个样式属性,只触发一次重绘

需求:需要写一个函数来修改一个DOM元素的几个样式,一般实现:逐个添加样式到DOM元素上;但问题是每修改一个样式,就会引起一次重绘。

function addStyle(element) {  element.style.fontWeight = bold;  element.style.textDecoration = none;  element.style.color = #000;
}

解决:创建一个class类名,将要修改的样式放在这个类名里,在需要的时候用JS给DOM元素添加这个类名;可以实现添加多个样式但只触发一次重排(改变元素位置或大小)或重绘(只改变样式不改变位置大小)

.addStyle {  font-weight: bold;  text-decoration: none;  color: #000;
}
function addStyle(element) {  element.className = addStyle;
}

2、在非渲染区修改DOM元素样式

上一个方法是修改一个DOM元素的样式,如果用相同的样式修改多个DOM元素,可以使用这个方法

需求: 写一个函数修改一个指定元素的子元素中所有超链接的样式名。实现:遍历每个超链接修改他们的样式名。问题:每修改一个,会导致一次重绘

function updateAllStyle(element, anchorClass) {  var anchors = element.getElementsByTagName(a);  for (var i = 0, length = anchors.length; i < length; i ++) {  anchors.className = anchorClass;       //替换类名
//   anchors.setAttribute("class","类名")   //替换类名
//   anchors.classList.add("类名")          //添加类名}
} 

解决:把被修改的元素从DOM中移除,修改所有样式后,再把这个元素插回到原来的位置。

为了完成这个复杂的操作,我们可以先写一个可重用的函数,它不但移除了这个DOM节点,还返回了一个把元素插回到原来的位置的函数  。

function removeToInsertLater(element) {  var parentNode = element.parentNode;  var nextSibling = element.nextSibling;  parentNode.removeChild(element);  return function() {  if (nextSibling) {  parentNode.insertBefore(element, nextSibling);  } else {  parentNode.appendChild(element);  }  };
}

有了上面这个函数,现在我们就可以在一个不需要解析渲染的元素上面修改那些超链接了  。这样只在移除和插入元素的时候各触发一次重解析  。

function updateAllAnchors(element, anchorClass) {  var insertFunction = removeToInsertLater(element);     //返回了一个闭包var anchors = element.getElementsByTagName(a);  for (var i = 0, length = anchors.length; i < length; i ++) {  anchors.className = anchorClass;  }  insertFunction();                 //这个闭包引用着removeToInsertLater()函数中的变量对象
}

创建插入新的DOM元素


1、插入元素动作放在最后

适合插入一个元素。在创建元素后,先给元素添加所有的样式,最后再把它插入到DOM里面。这个方法使创建一个元素的过程中只引起一次重排(回流)和重绘  。

需求:实现一个函数,在一个指定的父元素上插入一个新的元素(超链接) ,并且添加新元素的样式 。实现:创建元素,插入到DOM里,设置相应的属性  。缺点是插入元素、每添加一次样式属性都会引发重排重绘

unction addElm(parentElement, anchorText, anchorClass) {  var element = document.createElement(a);  parentElement.appendChild(element);    //先插入元素element.innerHTML = anchorText;       //再修改样式element.className = anchorClass;
} 

解决:把插入元素动作放在最后执行,就可以只进行一次重排重绘

var element = document.createElement(a);
element.innerHTML = anchorText;      //先修改样式
element.className = anchorClass;
parentElement.appendChild(element);    //最后插入元素到DOM中

2、通过文档片段对象(DocumentFragment)创建一组元素

适合创建并插入多个元素并只触发一次重排重绘。

先在 DOM之外创建一个文档片段对象(不需要解析和渲染),然后我们在文档片段对象中创建很多个元素,最后我们把这个文档片段对象中所有的元素一次性放到DOM里面去,只触发一次重排重绘  。

需求:写一个函数,往一个指定的元素上面增加10个超链接  。如果我们简单的直接插入10个超链接到元素上面,就会触发10次重解析  。

function addAnchors(element) {  var anchor;  for (var i = 0; i < 10; i ++) {  anchor = document.createElement(a);  anchor.innerHTML = test;  element.appendChild(anchor);  }
}

解决:先创建一个文档片段对象,把每个新创建的元素都插入到它里面去  。当我们把文档片段对象用appendChild命令插入到指定的节点时,这个文档片段对象的所有子节点就一起被插入到指定的元素里面,而且只需要触发一次重解析  。

function addAnchors(element) {  var anchor, fragment = document.createDocumentFragment();  for (var i = 0; i < 10; i ++) {  anchor = document.createElement(a);  anchor.innerHTML = test;  fragment.appendChild(anchor);  }  element.appendChild(fragment);
}

总结:


修改DOM元素属性:

  • 给元素添加修改新的类名

    • (el.classList.add("类名"),el.setAttribute("class","类名"),el.className=类名)
  • 在非渲染区修改元素属性,也即脱离文档流(移除元素,添加样式,插入元素;
    • parentNode.removeChild(el); parentNode.insertBefore(el, nextSibling); parentNode.appendChild(el);  )

创建并添加新的DOM元素

  • 插入元素放在添加样式后面执行

    • document.createElement(el); parentElement.appendChild(element)
  • 使用文档片段对象(DocumentFragment)创建一组元素
    • fragment = document.createDocumentFragment();fragment.appendChild(el);  element.appendChild(fragment);

JS性能优化——减少DOM操作次数相关推荐

  1. Node.js性能优化

    你不知道的Node.js性能优化 - 知乎 https://zhuanlan.zhihu.com/p/50055740 你不知道的Node.js性能优化 "当我第一次知道要写这篇文章的时候, ...

  2. 在dom最前面插入_前端性能优化之dom编程

    写在前面 总所周知,在前端的日常里面,采用JS操作DOM节点的情况占据了大多数.虽然现在有MVVM主流框架代替我们做了这些事情,但充分理解在DOM操作各种损耗问题,将有助于让我们更加理解和优化问题. ...

  3. js性能优化--学习笔记

    <高性能网站建设进阶指南>: 1.使用局部变量,避免深入作用域查找,局部变量是读写速度最快的:把函数中使用次数超过一次的对象属性和数组存储为局部变量是一个好方法:比如for循环中的.len ...

  4. 你不知道的Node.js性能优化,读了之后水平直线上升

    本文由云+社区发表 "当我第一次知道要这篇文章的时候,其实我是拒绝的,因为我觉得,你不能叫我写马上就写,我要有干货才行,写一些老生常谈的然后加上好多特技,那个 Node.js 性能啊好像 D ...

  5. vue nextTick深入理解-vue性能优化、DOM更新时机、事件循环机制

    一.定义[nextTick.事件循环] nextTick的由来: 由于VUE的数据驱动视图更新,是异步的,即修改数据的当下,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图 ...

  6. Next.js性能优化之ISR渲染入门和原理探索

    前言 术语说明: SSR -- 服务端渲染 SSG -- 静态生成 ISR -- 增量静态化 Date Fetch 函数 -- 本文特指服务端数据获取的几种函数 getStaticProps . ge ...

  7. js基础4 使用dom操作/getStyle/scrollHeight/协议滚动禁用例子/div随鼠标移动/冒泡/事件的委派/事件的绑定

    使用dom操作 <!DOCTYPE html> <html lang="en"> <head><meta charset="UT ...

  8. Java性能优化最易操作的10大技巧!

    编辑 | ShirleyZ 译文 | 班纳睿 .一叶障目  .learner 原文 | https://coyee.com/article/11753-top-10-easy-performance- ...

  9. innerhtml js执行_JS 中 DOM 操作

    封面图片来源:沙沙野 内容概览 获取元素 元素属性 value 属性 显示时间 计时器 节点的增删改查 JS 的 DOM 操作 获取元素 <! ​ 运行结果: 2. 元素的属性 <! ​ ...

最新文章

  1. View的生命周期方法和Activity生命周期方法关系
  2. 关于jdk1.5之后的自定拆装箱
  3. java 微型数据库_Java 9代码工具:使用Java微型基准测试工具的实践会话
  4. django连接mysql步骤_使用Django连接Mysql数据库步骤
  5. OSPF次末节区域配置 201
  6. Google云也想为中国企业服务,正与腾讯浪潮谈合作
  7. Hive对比传统数据库区别
  8. gatk过滤_vcf文件过滤
  9. 自定义滚动条、tbody加滚动条
  10. 树梅派应用16: 树莓派“瑞士军刀”扩展板教程 V1.X TO V2.X 的适配说明
  11. Selenium版本与浏览器版本
  12. AOSP ~ NTP ( 网络时间协议 )
  13. Re:从零开始的Spring Security Oauth2(二)
  14. 【论文阅读】(2022)A goal-driven ruin and recreate heuristic for the 2D variable-sized bin packing prob...
  15. JAVA飞信_java调用飞信接口发短信 - 贪吃蛇学院-专业IT技术平台
  16. java期末总结报告,请查收
  17. Nett源码剖析(2)NioEventloopGroup的创建2021SC@SDUSC
  18. 加速新基建,优锘科技的数字孪生可视化运营平台迎来最好时代
  19. 为什么医院治不好你的鼻炎
  20. Kruskal算法和并查集

热门文章

  1. 【Life系列】之我在底层的生活
  2. android 按钮带图标 阴影_Android实现图片添加阴影效果的2种方法
  3. idea 启用lombok
  4. html5 离线资源缓存,html5的离线缓存使用方法
  5. Android 9.0 SIM卡初始化流程
  6. windows服务ServiceProcess
  7. matlab/simulink光伏储能并网交直流发电系统仿真模型
  8. ubuntu刷新自己dns
  9. php yii2 sns,GitHub - szhsh/iisns: 基于 yii2 的 sns 社区系统,一站式解决社区建站
  10. 获取帐号密码的简单方法