什么是虚拟DOM
- 虚拟DOM(Virtual DOM)是使用JavaScript对象描述真实DOM!
- Vue.js中的虚拟DOM借鉴Snabbdom,并添加了Vue.js的特性。
- 例如: 指令和组件机制
为什么要使用虚拟DOM
- 避免直接操作DOM,提高开发效率
- 作为一个中间层可以跨平台
- 虚拟DOM不一定能够提高性能
- 首次渲染的时候会增加开销
- 复杂视图的情况下(如中大型的单页应用SPA)提升渲染性能
- 如果有频繁DOM操作的话,虚拟DOM在更新真实DOM之前,首先会通过diff算法,对比新旧两个虚拟DOM树对象的差异,最终把差异更新到真实DOM;而不会每次都操作真实DOM。
- 另外通过给节点设置key属性,可以让节点最大程度得到重用,避免大量的重绘。
虚拟DOM 代码演示
new Vue()实例时,render的定义中有个习惯命名为h的函数类型参数,参数h()函数实际上对应我们源码中的$createElement()。
h() 函数的作用是用来创建一个虚拟节点VNode,调用 h(tag, data, children) 函数的时候需要传入三(4)个参数:
- tag:标签的名称:string类型 或者 组件的选项对象;
- data:是用来描述tag的,如果tag是标签,data中可以设置标签的属性或者它定义的DOM的元素属性等等,还可以注册事件。
- children:可以是字符串或者是数组,
- 如果是字符串的话,是设置的tag标签里面的内容textContent;
- 如果是数组的话,是设置tag标签中的子节点,子节点也是vnode类型的。
这里的 h函数 跟 snabbdom中的有些类似,核心作用都是一样的,都是为了创建vnode。 只不过Vue中的 h函数 它里面支持组件 component,并且还支持 slots 插槽。
使用示例:
data: { msg: 'Hello World' },
render(h) {
// h(tag, data, children)
// return h('h1', this.msg)
// return h('h1', { domProps: { innerHTML: this.msg }})
// return h('h1', { attrs: { id: 'title' }}, this.msg)
const vnode = h('h1', { attrs: { id: 'title' }}, this.msg)
console.log(vnode)
return vnode
}
打印的VNode实例
VNode {
asyncFactory: undefined
asyncMeta: undefined
children: [VNode]
componentInstance: undefined
componentOptions: undefined
context: Vue {_uid: 1, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
data: {attrs: {…}}
elm: h1#title
fnContext: undefined
fnOptions: undefined
fnScopeId: undefined
isAsyncPlaceholder: false
isCloned: false
isComment: false
isOnce: false
isRootInsert: true
isStatic: false
key: undefined
ns: undefined
parent: undefined
raw: false
tag: "h1"
text: undefined
child: undefined
[[Prototype]]: Object
}
VNode相较于真实DOM还是少相当多内容的。
h1#title
__vue__: Vue {_uid: 1, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
accessKey: ""
align: ""
ariaAtomic: null
ariaAutoComplete: null
ariaBusy: null
ariaChecked: null
ariaColCount: null
ariaColIndex: null
ariaColSpan: null
ariaCurrent: null
ariaDescription: null
ariaDisabled: null
ariaExpanded: null
ariaHasPopup: null
ariaHidden: null
ariaInvalid: null
ariaKeyShortcuts: null
ariaLabel: null
ariaLevel: null
ariaLive: null
ariaModal: null
ariaMultiLine: null
ariaMultiSelectable: null
ariaOrientation: null
ariaPlaceholder: null
ariaPosInSet: null
ariaPressed: null
ariaReadOnly: null
ariaRelevant: null
ariaRequired: null
ariaRoleDescription: null
ariaRowCount: null
ariaRowIndex: null
ariaRowSpan: null
ariaSelected: null
ariaSetSize: null
ariaSort: null
ariaValueMax: null
ariaValueMin: null
ariaValueNow: null
ariaValueText: null
assignedSlot: null
attributeStyleMap: StylePropertyMap {size: 0}
attributes: NamedNodeMap {0: id, id: id, length: 1}
autocapitalize: ""