compile 部分已经讲完了
(compile部分分为 解析器 + 优化器+ 代码生成器),
终于走到了 render,今天就来给自己记录下渲染三部曲的第二部render,
(渲染三部曲= compile + render生成Vnode + 将Vnode通过 update 挂载到 页面上),
update里 有一系列 diff操作。
咦,render 内容不多的
噔噔噔噔
render 的作用大家应该清楚
就是 执行 compile 生成的 render函数,然后得到返回的 vnode 节点
比如现在存在这个简单的模板
经过 compile 之后,解析成了对应的 render 函数,如下
function render() {
with(this) {
return _c('div', {
attrs: {
"data": 111
}
},
[_v(111)])
}
}
看着这个莫名其妙的 render 函数,里面都是些什么东西?
不怕,主要是出现了两个函数,我们要探索的就是这两个东西
_c , _v
这个两个函数的作用,都是创建 Vnode,但是创建的过程不一样
并且 render 函数执行的时候,会绑定上 模板对应的实例 为上下文对象
模板是属于哪个实例的,就绑定哪个实例
render.call(实例)
再通过 with 的作用
调用 _c 和 _v 就相当于 vm._c 和 vm._v
什么是 vm._v
现在就来看看 vm._v 是哪里来的
function installRenderHelpers(target) {
target._v = createTextVNode;
}
installRenderHelpers(Vue.prototype);
由上面可知,每个Vue 实例都会继承有 _v 这个方法,所以可以通过 vm._v 直接调用
再来看看 _v 对应的 createTextVNode 的作用是什么
创建文本节点!!
看下源码
function createTextVNode(val) {
return new VNode(
undefined, undefined,
undefined, String(val)
)
}
比如这个模板
{ {data}} 虽然是字符串,但是也要作为一个子节点存在,所以就当做是 文本节点
而 data 的值是 111
然后 上面的模板就会得到这样的 Vnode 结构如下
什么是 vm._c
_c 是一个大头,render 的重中之重,先来看看他是怎么来的
function initRender(vm) {
vm._c = function(a, b, c, d) {
return createElement(vm, a, b, c, d);
};
}
Vue.prototype._init = function(options) {
initRender(this)
}
在实例初始化的时候,就会给实例绑定上 _c 方法
所以,vm 可以直接调用到 _c
看了上面的源码,看到 _c 内部调用了 createElement
那就来看看createElement 的源码吧
个人已经简化得非常简单,觉得不偏离我们的主题就可以
function createElement(
context, tag, data, children
) {
return _createElement(
context, tag, data, children
)
}
function _createElement(
context, tag, data, children
) {
var vnode;
if (如果tag是正常html标签) {
vnode = new VNode(
tag, data, children,
undefined, undefined,
context
);
}
.....如果tag是组件名,就特殊处理 ,处理流程已经省略
if (Array.isArray(vnode))
return vnode
else {
// ...动态绑定 style ,class,代码已经省略
return vnode
}
}
你一看