什么是虚拟DOM?
虚拟 DOM (Virtual DOM )这个概念相信大家都不陌生,简单地说,就是一个普通的 JavaScript 对象,包含了 tag、props、children 三个属性,以这三个属性来描述一个DOM节点,每组描述就是一个VNode,整个VNode的集合就是一个虚拟DOM树。
虚拟DOM有什么优点?
减少DOM操作
虚拟DOM可以将多次操作合并为一次操作,譬如往网页中用添加1000个节点,使用JS是一个接一个操作的,DOM操作需要1000次,而虚拟DOM是一次性操作的,
虚拟DOM借助DOM diff可以把多余的操作省掉,比如添加1000个节点,其中990都没有更改,其实只有10个是需要更改的,那么操作这10个节点就可以了。
跨平台
虚拟DOM不仅可以变成DOM,还可以变成小程序、IOS应用,安卓应用,因为虚拟DOM本质上是一个JS对象。
虚拟DOM长什么样子
React
const vNode = {
key: null,
props: {
children: [ //子元素们
{type:'span',...},
{type:'span',...}
],
className:'red' //标签上的属性
onClick:()=>{} //事件
},
ref:null,
type:'div', //标签名或者组名
...
};
Vue
const vNode = {
tag: "div", //标签名或者组件名
data: { //标签上的属性
class: "red",
on: { //事件
click: () => {},
},
},
children: [ //子元素们
{ tag: "span",... },
{ tag: "span",... }
],
...
};
如何创建一个虚拟DOM
React.createElemernt
createElement("div", { className: "red", onClick: () => {} },
[ createElement("span", {}, "span1"),
createElement("span", {}, "span2"),
]);
==========================================================================================
使用JSX //通过babel转译
<div className="red" onClick={() => {}}>
<span>span1</span>
<span>span2</span>
</div>;
Vue(只能在render函数里得到h)
h(
"div",
{
class: "red",
on: {
click: () => {},
},
},
[h("span", {}, "span1"),
h("span", {}, "span2")]
);
=======================================================================================
template //使用Vue-loader转译
<div class="red" :Click="fn">
<span>span1</span>
<span>span2</span>
</div>;
虚拟DOM有什么缺点?
创建虚拟DOM需要额外的创建函数,譬如createElement或者Vue的h函数,但是可以通过JSX来简化成XML写法,但是这样又会暴露出一个缺点,就是React和Vue会极度的依赖打包工具,浏览器只能读懂JS语言,所以需要通过babel和Vue-loader来转译。
DOM diff 是什么?
DOM diff就是一个函数,我们称之为patch,用作比较两个虚拟DOM的区别,其本质就是对比两个对象的区别。
patches=patch(oldVNode,newVNode)
我们可以把虚拟DOM 想象成一个树形。
<div :class="red">
<span v-if="y">{string1}</span>
<span> {string2} </span>
</div>
数据发生变化时
class发生改变,从red变成green
DOM diff会从上到下,从左到右的去对比,发现:
- div的标签类型没有发生变化,但是class属性发生变化,所以更新DOM对应的属性
- 元素没有发生改变,不更新
当y从true变为了false
- div和其属性没有发生变化,所以不更新。
- 检查子元素1和2,发现子元素2的span标签删除。
- 然后子元素1的span内的hello 变成了world,然后进行更新。