Vue2.x 源码阅读思路笔记

目前公司主要技术栈是Vue,为了更好的使用,完成的了解Vue的原理是很有必要的。刚开始直接阅读Vue源码时,发现自己阅读的效率很低。偶然间(其实不偶然)
在Github中发现了这份笔记 如何学习Vue2源码,完整的记录了实现Vue框架的完整过程。

我fork了作者的项目,跟着作者的思路如何学习Vue2源码,完整走了一遍如何实现一个2.X版本的Vue。阅读过程中我拉了一个新分支如何学习Vue2源码(带注释),添加了详细的注释,方便自己记忆。通过阅读作者的github,节省自己大量时间~

下面内容为自己的笔记,自己整理思路用。
建议阅读这位大神的github:如何学习Vue2源码
我的阅读记录: 如何学习Vue2源码(带注释)

Virtual DOM

参考:https://mp.weixin.qq.com/s/QXQAPEXojB9Zvri6GdXcJg

  • 生成virtual DOM
    • 用js对象模拟DOM树(html语法树?)
  • render真实DOM
    • virtual对象的render函数
  • 生成新的virtual DOM
  • render新的真实DOM
  • diff新旧真实DOM,保存变更的patches
    • diff算法复杂度问题
    • 深度优先遍历,每遍历一个node同时跟新的树比较,记录差异
    • 差异类型,不同类型处理方式不一致
    • 列表对比算法,调换顺序最优解?
  • 在旧的真实DOM上应该patches
    • 不同的patch类型,不同的处理方式

HTML parser

  • Token解析
    • HTML字符串 --> Token数组
  • 语法树解析
    • Token数组 --> HTML AST
  • VNode树
  • Dom树

首先有2个重要的概念要留意,将会贯穿后续的文章:静态、动态(runtime)。
我们给一下以下简单的定义:
静态: 任何时刻运行转换函数,同一个输入得到的数据结构都是一致的
动态: 存在某一时刻运行转换函数,同一个输入得到的数据结构是不一致的
所以上边所有涉及到的数据结构可以归为:
字符串 是 静态 的
HTMLElment Token 流 是 静态 的
AST 树 是 静态 的
VNode 树 是 动态 的
DOM 树 是 动态 的

构建一个最简单的数据绑定的Vue

AST树、VNode render、VNode三者之间的渐进关系
在这里插入图片描述

VNode 的属性 attrs 和 props

在这里插入图片描述

控制语句

v-if v-else-if v-else v-for
新增语法步骤同上及几章:

  • parse阶段增加解析v-for v-if部分的代码,在AST上添加这部分语法的属性
  • 生成render函数阶段,同样要增加将AST转换成render函数的fn,
  • 生成Vnode阶段,在单用render函数的时候,需要将v-if语法转换为实际的VNode对象
  • path阶段 将VNode树转换成DOM树

响应式原理

基于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 me</button>

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

生命周期

在这里插入图片描述

  1. new Vue()
  2. 初始化生命周期、往vue实例上绑事件、方法
    这里只的事件、方法,并不是用户自己绑定的method、data之类的数据,而是Vue实例本身的一些内部方法。
  3. 执行钩子:beforeCreate()
    beforeCreate()钩子中无法访问到,data、method、$el等数据
    $el挂载点,也就是vue生成的dom挂载的地方
  4. 初始化状态
    简单来说就是初始化method、data,监听数据之类的操作
  5. 执行钩子:created()
    data、method方法已经能访问了,但是还没有挂载点信息
  6. 是否有挂载点?
    有:获取模板信息(有无template,两种情况),编译 -> vnode -> render函数 -> Dom -> diff -> patch
    无:暂停执行,知道使用.$mount()手动挂载后,继续执行
  7. 执行钩子:beforeMount()
    .$el中已经有挂载点了,但是dom资源还没有渲染
  8. 将VNode渲染成Dom,并挂载到挂载点上。
    $el得到更新。
  9. 执行钩子mounted()
    挂载完成。
  10. data改变时,触发监听。
  11. 执行beforeUpdate()
    此时仅监听到了data改变,还未做出操作
  12. diff VNode -> patch
    对比VNode变化,更新dom
  13. 检测到页面销毁(.$destroy()被执行)
  14. 执行钩子beforeDestroy()
  15. 移除data、mothod、watcher、components、event listener等
  16. 执行钩子destroyed()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值