前言: 去年花了几天时间尝试解读vue源码,可惜基础不够再加上项目压着,无疾而终。今年继续挑战~,let‘s go
本文算是自己学习源码的一篇整合笔记,会直接跳过很多细节,先把整体逻辑理一遍。
1.先写一个简单的demo吧
2.vue构造函数接收到即将要创建vm的options
找找_init
在原型链上找到了它。
3. mergeOptions整合、初始化部分属性
在接收到options之后,会先交给mergeOptions整合一遍部分属性,它负责按照预设定逻辑合并上级options(如果有)和规范prop,inject, Directives的命名。
并且它还会接受上级mixins(上级组件和全局)
4.initProxy创建proxy代理
下一步是由initProxy给实例创建proxy代理,代理的位置在vm._renderProxy
5.initLifecycle创建生命周期
这一步给vm添加很多的属性,代码上可以看到,它先给vm继承了族谱(如果有父级),
随后预定义了$refs和$children等比较眼熟的属性,这些属性在后面的阶段中都会用上,
其中比较特殊的是_isMounted和_isDestroyed等,它们主要是标记组件状态的,比如
_isDestroyed,一个已经销毁的组件自然不需要做很多操作了
6.initEvents初始化父级事件
这一步骤主要是初始化父组件添加到当前vm的事件, 就不深入了。
7.initRender创建vm渲染逻辑以及接受$attrs、$listeners和插槽
这里比较重要的是vm._c和vm.$createElement的区别只有对于render函数中children参数的处理方式,个人理解上,后者是整体渲染的时候用,前者则是只有本级dom更新渲染的时候使用。
8.beforeCreate 第一次钩子触发了
9.initInjections获取上级注入的依赖
10.初始化vm基础的常见属性:props,methods, data, computed, watch
11.initProvide 初始化依赖注入
12.created第二个钩子被触发,vm数据已经准备就绪
13.获取vm的render函数
如果options中不包含render函数,那么这时候compileToFunctions函数就要开始工作了,它的工作主要是将template模板编译成ast对象,随后该对象将被转换成独有的render函数,
列如我的第一步创建的demo,他的render函数如下:
是不是密密麻麻 看着眼睛疼。 我格式化一下:
function anonymous() {
with(this){
return _c(
'div',
{
attrs:{"id":"app"},
on:{"click":c}
},
[
_l(
(b),
function(item){
return _c('p',
{
key:item,
staticClass:"ppp"
},
[_v(" "+_s(item))])
}
),
_v(" "),
_c('p',[_v(_s(d))])
]
,2
)
}
}
眼熟了吧。 是不是和平时写的render函数一个样子(其中还有一些内置函数就不说了)
14.beforeMount,render函数已就绪,可以准备渲染视图了,第三个钩子被触发
15.给vm添加监控器,以及初次渲染页面
并且在第一次绑定时,_watcher手动触发了一下update,于是此时页面终于开始第一次渲染视图。
16.mounted,第四个钩子被触发,vm实例初始化全部完成。
以上就是初步整理的vm初始化大致过程,还有很多东西没有细讲,比如watch监视器如何工作,render函数具体如何更新视图等,如果还有时间就下次再整理一下。
ps: 如果有人需要我备注过的vue源码,我可以放在我的个人网站的工具箱里,请自取