Vue 的源码结构比较绕,同时使用了大量的面向对象的高级技巧。重写方法,扩展方法,多态等应用。从 Vue 实例的加载过程就可以看出来,这一节重点看看 Vue 的源码加载流程是什么。

前言

vue已是目前国内前端web端三分天下之一,同时也作为本人主要技术栈之一,在日常使用中知其然也好奇着所以然,另外最近的社区涌现了一大票vue源码阅读类的文章。在下借这个机会从大家的文章和讨论中汲取了一些营养,同时对一些阅读源码时的想法进行总结,出产一些文章,作为自己思考的总结。

前备知识

  • Flow
  • ES6语法
  • 常用的设计模式
  • 柯里化等函数式编程思想

一、vue简介和初始化过程

vue的源码结构如下:

A.compiler 编译用的

a.vue 使用字符串作为模板

b.在编译文件夹中存放对 模板字符串的 解析的算法, 抽象语法树, 优化等

B.core 核心, vue 构造函数, 以及生命周期等方法的部分

C.platforms 平台

a.针对运行的环境 ( 设备 ), 有不同的实现

b.也是 vue 的入口

D.server 服务端, 主要是将 vue 用在服务端的处理代码 ( 略 )

E.sfc, 单文件组件 ( 略 )

F.在编译文件夹中存放对 模板字符串的 解析的算法, 抽象语法树, 优化等shared 公共工具, 方法

二、Vue对象

在使用vue时我们知道都是使用new Vue(),来将vue的实例挂载到dom对象上从而运用数据驱动的方式来扩展我们的代码,我们首先来看一下Vue的定义

从源头上看来自core目录下的index.js文件

在js中一切皆函数,其实Vue就是一个函数,在初始化的时候执行原型链上的_init方法,vue没有把所有的方法都写在函数内部,这样从代码上来说,每次实例化的时候不会生成重复的代码。

主要还是代码结构更清晰,利用mixin的概念,把每个模块都抽离开,这样代码在结构和扩展性都有很大提高,这里的每个mixin先不说,先看以一下整体结构,这里定义完还要被core里的index.js再次包装调用initGlobalAPI(Vue)来初始化全局的api方法。

在web下runtime文件夹下引用再次封装,vue是分为运行时可编译和只运行的版本,所以如果需要编译,在Vue原型上添加了$mount方法。

三、运行机制

当我们在 main.js 里 new Vue( ) 后,Vue 会调用构造函数的 _init( ) 方法,这个方法是位于 core/instance/index.js 的 initMixin( ) 方法中定义的

我们可以看看 init( ) 这个方法到底进行了哪些初始化:

这里 _init() 方法中会对当前 vm 实例进行一系列初始化设置,比较重要的是初始化 State 的方法 initState(vm) 的时候进行 data/props 的响应式化,这就是传说中的通过 Object.defineProperty() 方法对需要响应式化的对象设置 getter/setter,以此为基础进行依赖搜集(Dependency Collection),达到数据变化驱动视图变化的目的。

最后检测 vm.$options 上面有没有 el 属性,如果有的话使用 vm.$mount 方法挂载 vm,形成数据层和视图层的联系。这也是如果没有提供 el 选项就需要自己手动 vm.$mount('#app') 的原因。

我们看到 created 钩子是在挂载 $mount 之前调用的,所以我们在 created 钩子触发之前是无法操作 DOM 的,这是因为还没有渲染到 DOM 上。

 四、总结

一张图看一下整个流程


技术全能渣男
40 声望1 粉丝