最近在审核新人代码的时候,看到新人在vue中使用了document.getElementsByClassName
批注了尽量不操作原生dom,想附上原因,( ̄▽ ̄)" 发觉已然忘了为何不用,于是乎,复习一回。
主要从查和增删改两个角度来分析虚拟dom的优点。
一、查
区别:
真实DOM操作:
document.get...
查询的是整个节点树。
ParentNode.querySelector()
和ParentNode.querySelectorAll()
是有范围地查询ParentNode下的节点,过程中是需要根据传入的参数来比对节点上的属性。
虚拟DOM操作:this.$refs.refName
查询的是当前组件实例上的属性$refs
对象中key为refName的属性。
观察一下当前组件实例:console.log(this)
课外复习:
参考:Document - Web API 接口参考 | MDN
真实DOM查询节点的几种方法:
getElementById()
getElementsByClassName()
getElementsByName()
getElementsByTagName()
getElementsByTagNameNS()
document.querySelector()
ParentNode.querySelector()
document.querySelectorAll()
ParentNode.querySelectorAll()
参考:ref - API — Vue.js
虚拟DOM查询节点的方法:this.$refs.refName
二、增删改
普通的真实dom作增删改时会引起浏览器的重排和重绘。
old:在虚拟dom出现之前比较好的操作是在文档片段createDocumentFragment
或者拷贝节点cloneNode
中一次性把需要的增删改都做好,再把这个片段或节点放到页面中。
// bad
let ul = document.querySelector('#mylist');
ul.append(li)
ul.append(li)
ul.append(li)
// good,两次重排重绘
let ul = document.querySelector('#mylist');
ul.style.display = 'none'; // 减少重绘
ul.append(li)
ul.append(li)
ul.append(li)
// better,一次重排重绘
let fragment = document.createDocumentFragment();
fragment .append(li)
fragment .append(li)
fragment .append(li)
ul.appendChild(fragment);
new:现在几大主流框架都实现了虚拟dom,并且实现了新旧节点比较,这就解决了以前多次重排重绘的问题,且减少了代码量。
区别:
真实DOM操作:真实DOM增删改 + (可能较多节点)重排与重绘
虚拟DOM操作:虚拟DOM增删改 + 真实DOM差异增删改(这与Diff算法效率有关) + (较少节点)重排与重绘