目前公司主要技术栈是Vue,为了更好的使用,完成的了解Vue的原理是很有必要的。刚开始直接阅读Vue源码时,发现自己阅读的效率很低。偶然间(其实不偶然)
在Github中发现了这份笔记 如何学习Vue2源码,完整的记录了实现Vue框架的完整过程。
我fork了作者的项目,跟着作者的思路如何学习Vue2源码,完整走了一遍如何实现一个2.X版本的Vue。阅读过程中我拉了一个新分支如何学习Vue2源码(带注释),添加了详细的注释,方便自己记忆。通过阅读作者的github,节省自己大量时间~
下面内容为自己的笔记,自己整理思路用。
建议阅读这位大神的github:如何学习Vue2源码。
我的阅读记录: 如何学习Vue2源码(带注释)
参考:https://mp.weixin.qq.com/s/QXQAPEXojB9Zvri6GdXcJg
首先有2个重要的概念要留意,将会贯穿后续的文章:静态、动态(runtime)。
我们给一下以下简单的定义:
静态: 任何时刻运行转换函数,同一个输入得到的数据结构都是一致的
动态: 存在某一时刻运行转换函数,同一个输入得到的数据结构是不一致的
所以上边所有涉及到的数据结构可以归为:
字符串 是 静态 的
HTMLElment Token 流 是 静态 的
AST 树 是 静态 的
VNode 树 是 动态 的
DOM 树 是 动态 的
AST树、VNode render、VNode三者之间的渐进关系
v-if v-else-if v-else v-for
新增语法步骤同上及几章:
基于Object.defineProperty实现data的数据监听,set 写操作的时候,我们要调用 vm._update() 进行视图更新。
深入理解Vue的computed实现原理及其实现方式
obsever、dep、watch之间的关系:https://github.com/coderzzp/vue-come-true/tree/master/vue-come-true-First
深入浅出 - vue变化侦测原理
详细源码分析:https://segmentfault.com/a/1190000014360080
observe ->
walk ->
defineReactive ->
get ->
dep.depend() ->
watcher.addDep(new Dep()) ->
watcher.newDeps.push(dep) ->
dep.addSub(new Watcher()) ->
dep.subs.push(watcher)
set ->
dep.notify() ->
subs[i].update() ->
watcher.run() || queueWatcher(this) ->
watcher.get() || watcher.cb ->
watcher.getter() ->
vm._update() ->
vm.__patch__()
时间的处理与之前属性的处理基本一致:
a. 以下 HTML:
<button v-on:click="clickme">click mebutton>
b. 解析后得到的 AST 节点:
evtAstElm = {
type: 1,
tag: 'button',
events: {
'click': { value: 'clickme' }
},
children: [ /* blabla.. */ ]
}
c. 生成的 render code:
_c('button', {
on: { "click": clickme }
}, [ _v("click me")] )
d. 得到一个带属性的 VNode 节点:
VNode {
tag: 'button',
data: {
on: { "click": clickme }
},
children: [ /* blabla.. */ ]
}
c. 生成的 render code ( clickme 函数需要代理到当前的 vm 对象上,同时绑上 vm 这个运行时 context):
_c('button', {
on: { "click": clickme }
}, [ _v("click me")] )
e. 最后渲染在 dom 上的时候:
buttonDom.addEventListener('click', clickme)
源码的事例 https://github.com/raphealguo/how-to-learn-vue2-blob/blob/master/articles/2.4.1.md
beforeCreate()
beforeCreate()
钩子中无法访问到,data、method、$el等数据created()
编译 -> vnode -> render函数 -> Dom -> diff -> patch
.$mount()
手动挂载后,继续执行beforeMount()
.$el
中已经有挂载点了,但是dom资源还没有渲染$el
得到更新。mounted()
beforeUpdate()
diff VNode -> patch
.$destroy()
被执行)beforeDestroy()
destroyed()