初学JS小记(二)——dom操作与优化

一、什么是DOM

       DOM其实是针对html和xml提出的一个API(应用编程接口)。什么意思呢?就是为了我们更好的操作html或者xml中的元素,而提出来一系列的操作标准,并且将这些标准用代码实现了。我们在实际中,只需要操作这些接口就可以访问、增加、删除文档中的元素。

       DOM将这个文档描绘成一个多层次的节点树,一切的操作都是在这个节点树上进行的。DOM1其实就是最开始的W3C对文档操作规定的基础标准,这个标准里面实现了基本的文档操作:查询、删除、替换、增加。一下我们常用的函数都属于DOM1:

document.getElementById();
document.getElementsByTagName();
div.appendChild();
div.removeChild();
div.replaceChild();
         后面为了更好的操作文档,又对DOM1进行了扩展,主要分为:selectors API 和 HTML5两方面的扩展。

         selectors API中主要是两个函数:querySelector()和querySelectorAll()。这两个函数主要是可以通过不用的CSS选择符来选择元素。不同之处在于querySelector()只返回第一个符合条件的节点,而querySelectorAll()返回所有符合条件的节点。

        HTML5新增了一系列浏览器应该支持的javascript APIS 接口。比较重要的如下:

        1.document.getElementsByClassName()

        可以通过类名获取到节点。

        2.classList

        在这之前访问一个元素的具有哪些class,只能通过className,而className返回的是class中所有的字符串,更改、删除和增加新的class非常的不方便,需要操作整个字符串。

        classList提供了下列一系列的接口来操作class,极大的方便了对节点class的操作。

var div = document.getElementById('div');
div.classList.add('bg');       //增加bgdiv.classList.contains('bg');  //是否包含bg类,有返回true,否则返回false
div.classList.remove('bg');    //删除bgdiv.classList.toggle('bg');    //若存在bg类,则删除,否则添加bg

         3.readyState与compatMode

         document.readyState :  

              loading:     文档正在加载。

               complete: 文档加载完毕。

         compatMode:

              CSS1Compat : 浏览器工作在标准模式

              backCompat:浏览器工作在混杂模式

          4.innerHTML和outerHTML


二、DOM2与DOM3 

       DOM2和DOM3是在DOM1的基础上,为了更好的交互,进行了一系列的接口扩展,以满足操作xml的需要求,同时提供更好的错误处理能力及特性检测能力。DOM2只是在DOM1原有的类型上增加了新的属性和方法,并没有增加新的类型。而DOM3不仅在DOM1原有的类型上增加了新的属性和方法,而且增加了新的类型。


三、提高DOM操作性能的几个小技巧

        我们都知道对界面上的元素进行一系列的操作时,会导致浏览器对界面的重绘。如果只是进行少量的操作,基本不会有什么影响,但是如果操作大量的元素,或频繁地在界面中添加、删除元素,将严重影响性能。有一下技巧可以避免这种情况。

      1.尽量使用innerHTML/outerHTML,而不是createElement().

       使用innerHTML/outerHTML直接利用字符串拼接的方式将创建一个HTML解释器。这个解释器是在浏览器级别的代码(通常是c++编写的)基础上运行的,因此比执行JavaScrip快得多。不可以避免地,创建和销毁HTML解释器也会带来性能的损失,所以最好将设置innerHTML/outerHTML的次数控制在合理的范围内。eg:

for (var i = 0; i < count;i++) {
    ul.innerHTML += '<li style="margin-left: 20px">item' + i + '</li>';
}
       如上代码就多次读取和改变ul的innerHTML,这样每次循环就访问了两次innerHTML,效率过低。所以,建议先使用一个字符串保存所有的值,最后在赋值给innerHTML。eg:
var temp ='';
for (var i = 0; i < count;i++) {
    temp += '<li style="margin-left: 20px">item' + i + '</li>';
}
 ul.innerHTML = temp;

      2.使用DocumentFragment缓存操作,这样只会引起一次重绘。

        DocumentFragment(文档片段)是DOM中的一种节点类型。它在文档中没有相应的标记,是一种轻量级的文档,可以包含和控制节点,但是又不需要暂用文档中额外的资源。所以,虽然不能将文档片段直接加入到文档中,但是可以将DocumentFragement当做一个“缓存仓库”来使用。

       将文档中的节点添加到文档片段后,文档树中就不会存在该节点了,即在浏览器中看不到该节点。添加到文档片段中的新节点同样也不属于文档树。可以通过appendChild()/insertBefore()将文档片段中的节点添加到文档中(不是将文档片段加到界面,而是文字片段中的子节点。文档片段永远不能称为文档树的一部分),此时,节点从文档片段中移除。

var fragment = document.createDocumentFragment();
for (var i = 0; i < count;i++) {
    var li = document.createElement('li');
    li.style.marginLeft = 20 + 'px';
    li.appendChild(document.createTextNode('item' + i));
    fragment.appendChild(li);
}
console.log(fragment.children.length);
ul.appendChild(fragment);
console.log(fragment.children.length);

      在上述代码中我们先创建一个fragment来保存每次创建的li节点。最后再将fragment中的所有li添加到ul中。两次输出,一次是count,一次是0。因为节点一旦添加到文档中就从文档片段中删除。这样,我们只改变了一次文档的结构。

      3.对需要频繁添加或删除子节点的元素先设置“displag:none”,在完成所有操作之后再设置元素可见。

      4.减少获取nodeList、namedNodeMap、HTMLCollect类型的元素的次数。

      这三种类型是界面上某一类节点的动态集合。也就是说,界面上节点的变化也会反映到这几种类型的值上。每次访问这几种类型,就需要查询页面一次。eg:

var li = ul.getElementsByTagName('li');
for (var i = 0;i < li.length; i++) {
    var liItem = document.createElement('li');
    ul.appendChild(liItem);
}

     以上代码本来的是想在将ul之中的li的数量增加一倍。但是这样书写会有一个致命的问题,for循环永远无法结束。因为每次循环就会在ul中新增加一个li,在每次访问li.length就会重新计算一次界面当前ul中的li的数量,而不是使用最开始的ul中的li的 数目,这样i永远不能增加到li.length的值。正确的做法是先保存li.length的值,而不是在每次循环中访问一次。每次循环中访问一次就需要重新在界面中进行计算,比较耗时,在数目较多的时候,对系统性能有影响。 

var li = ul.getElementsByTagName('li');
var len = li.length;
for (var i = 0;i < len; i++) {
    var liItem = document.createElement('li');
    ul.appendChild(liItem);
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值