虚拟DOM的概念
虚拟DOM(Virtual DOM)是使用js对象描述真实DOM。通过对比变化前后的虚拟DOM,可以精确定位到视图的变化,只修改变化部分的视图,提高复杂视图变化时的渲染效率。
Vue中的虚拟DOM
Vue中的虚拟DOM借鉴了Snabbdom,其模块机制,钩子函数以及diff算法和Snabbdom几乎一致,但Snabbdom的基础上添加了Vue的特性,如指令和组件机制。
虚拟DOM的优缺点
优点
- 避免直接操作
DOM,提交开发效率。 - 作为中间层可以实现跨平台。
- 复杂视图情况下可以提升渲染性能
缺点
- 首次渲染会增加开销,因为要维护额外的虚拟
DOM。 - 简单视图情况下会增加额外的成本。在理想状态下,每次数据的修改都能直接定位到视图的修改,这样比使用虚拟
DOM效率更高,消耗的资源更少。
render函数中的参数h函数
render函数中的参数h函数和Snabbdom中的h函数是类似的,用来创建虚拟DOM,接收四个参数,前三个参数和Snabbdom中的h函数一致,第一个是字符串类型的标签或者选择器,第二个参数是一个可选的选项对象,第三个参数是表示子元素,可以是一个字符串或一个数组,也是可选的。
const vm = new Vue({
el: '#app',
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 null
},
data: {
msg: 'Hello Vue'
}
})
h函数即vm.$createElement方法。
h函数最终返回一个VNode对象(即虚拟DOM对象)。包括以下核心属性:
tag:调用h函数传入的第一个参数,表示要创建节点的选择器。data:调用h函数传入的第二个参数,描述节点的属性对象。children:调用h函数传入的第三个参数,表示节点的子元素信息。text:节点的文本内容。elm:节点对应的真实DOM,节点转化为真实DOM之后将保存在该属性。key:节点标记,为了复用节点。
VNode的创建过程
即createElment的调用过程:
-
mountComponent中定义了updateComponent,创建Watcher时会将updateComponent传入,数据变化时会调用updateComponent重新渲染。而updateComponent内部则是调用了vm._render方法。

-
_render方法时在instance/render.js文件中定义的。方法内部是通过调用用户传入的render方法来创建虚拟DOM对象。调用render方法时会传入vm.$createElement(即h函数)作为参数//vm._renderProxy = vm vnode = render.call(vm._renderProxy, vm.$createElement) -
vm.$createElement内部调用createElement方法,其内部将调用_createElement方法生成虚拟DOM,_createElement方法实现如下:export function _createElement ( context: Component, tag?: string | Class<Component> | Function | Object, data?: VNodeData, children?: any, normalizationType?: number ): VNode | Array<VNode> { if (isDef(data) && isDef((data: any).__ob__)) { process.env.NODE_ENV !== 'production' && warn( `Avoid using observed data object as vnode data: ${ JSON.stringify(data)}\n` + 'Always create fresh vnode data objects in each render!', context ) return createEmptyVNode() } // <component v-bind:is="currentTabComponent"></component> // object syntax in v-bind if (isDef(data) && isDef(data.is)) { tag = data.is } if (!tag) { // in case of component :is set to falsy value return createEmptyVNode() } // warn against non-primitive key if (process.env.NODE_ENV !== 'production' && isDef(data) && isDef(data.key) && !isPrimitive(data.key) ) { if (!__WEEX__ || !('@binding' in data.key)) { warn( 'Avoid using non-primitive value as key, ' + 'use string/number value instead.', context ) } } // support single function children as default scoped slot if (Array.isArray(children) && typeof children[0] === 'function' ) { data = data || { } data.scopedSlots = { default: children[0] } children.length = 0 } if (normalizationType === ALWAYS_NORMALIZE) { //用户传入的render函数 // 返回一维数组,处理用户手写的 render children = normalizeChildren(children) } else if (normalizationType === SIMPLE_NORMALIZE) { // 把二维数组,转换成一维数组 children = simpleNormalizeChildren(children) } let vnode, ns if (typeof tag ===

本文深入解析Vue2.x中的虚拟DOM概念,探讨其借鉴自React的机制以及Vue特有的指令和组件。虚拟DOM在复杂视图渲染中能提升性能,但也存在首次渲染开销。文章详细介绍了`render`函数、虚拟DOM的创建过程、更新过程以及`patch`函数的源码解析。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



