Vue实例创建之vnode创建

前言

上一篇文章中分析了html->vnode主要的处理过程,实际上主要是parse + generate解析template构建render函数的过程,实际上vnode的创建是在render执行过程中触发的。

本文主要分析render调用过程以及该过程vnode的创建。

具体分析

在render构建和调用那篇文章中,就提及render的调用实际上是Watcher实例对象创建触发的,主要的处理逻辑如下:
在这里插入图片描述

从上图的主要逻辑点可以看出,$mount的处理过程中主要会构建Watcher实例,而Watcher实例最终会执行Vue实例方法_update和_render,这里是核心了。

_render实例方法

_render实例方法实际上主要的处理点就是执行render函数返回其执行结果,核心代码逻辑如下:

var vnode = render.call(vm._renderProxy, vm.$createElement);
return vnode;

在上一篇文章中,知悉了render函数的基本构造,还使用如下实例:

<div>
	{{ text }}
</div>

得到的render函数如下:

const render = new Function("with(this) {return _c('div', {attrs: {'id': 'app'}}, [_v('\n' + _s(text) + '\n)])}")

在执行_render函数实际上就是执行render函数,此时会调用:

vm._c:即$createElement
vm._s:即toString函数
vm.text:即触发data响应式,会调用getter函数,获取text最新的值

_s实例方法

_s实例方法的源码如下:

function toString(val) {
	return val === null 
				? ' ' 
				: typeof val === 'object' 
					// 格式化对象,并指定缩进为2个空格
					? JSON.stringify(val, null, 2) 
					: String(val);
}

主要就是处理null、对象以及数组形式的数据等将其转换为字符串。

_v实例方法
function createTextVNode(val) {
	return new VNode(undefined, undefined, undefined, String(val));
}

_v实际上就是createTextVNode函数,用于创建文本类型的虚拟DOM

_c实例方法

该方法是vnode创建的实际出发点,Vue核心方法之一,具体源码如下:

vm._c = function(a, b, c, d) {
	return createElement(vm, a, b, c, d, false);
};

createElement整个的处理逻辑如下:
在这里插入图片描述

上图是根据最基本的实例梳理的主要脉络,实际上还有很多复杂的处理,但是最为核心的就是调用VNode构造函数创建虚拟DOM:

new VNode(tag, data, children, undefined, undefined, context)

这里需要说明下createElement中a、b、c、d参数表示的含义:

  • a:tag,表示标签名
  • b:data,表示属性、事件、class、props等的配置对象
  • c: children,表示子节点
  • d:normalizationType,表示类型,即要如何处理children中的数据

VNode构造函数

VNode构造函数实际上就是定义相关属性,VNode中重要的属性有:

  • tag:当前标签名
  • data:标签属性、props、事件等对象集合
  • children:子节点的VNode数组
  • text:当前标签文本内容
  • context:上下文对象,即Vue实例对象
var VNode = function(tag, data, children, text, elm, context, componentOptions, asyncFactory) {
	this.tag = tag;
	this.data = data;
	this.children = children;
	...
}

简单实例_render函数的处理就是上面整个逻辑:

_render() -> render -> createElement(或createTextVNode)-> new VNode

_render执行render函数生成DOM结构的vnode,接下来就是_update实例方法的调用了。

_update实例方法

_update中处理实际上有两个主要点:

  • vm._vnode相关处理,两点:prevNode = vm._vnode,vm._vnode = vnode
  • vm.__patch__的调用

prevNode记录更新前的vnode,如果是初始化,那么prevNode就是空,调用__patch__实现vnode -> html的过程,也是diff算法的实现过程,是整个Vue中核心点之一。

_update核心源码如下:

var prevNode = vm._vnode;
vm._vnode = vnode;
if (!prevNode) {
	// 初始化
	vm.$el = vm.__patch__(vm.$el,vnode, hydrating, false);
} else {
	// 更新
	vm.$el = vm.__patch__(prevNode, vnode);
}

总结

从上面的分析中可知,vnode的创建实际上是render函数执行过程中_v、_c函数触发的,而响应式data数据也是通过调用触发的,这些都取决于render函数的结构:

with(this) {
	// code
}

而this === Vue实例,触发响应式data数据的调用以及相关vnode虚拟DOM的构建。

而_update则负责比较dom节点并替换。

猜你喜欢

转载自blog.csdn.net/s1879046/article/details/82910130
今日推荐