Vue源码分析(一) : new Vue () 作了什么

Vue源码分析(一) : new Vue() 作了什么
author: @TiffanysBearjavascript

在了解new Vue作了什么以前,咱们先对Vue源码作一些基础的了解,若是你已经对基础的源码目录设计等有基础的了解的话,能够跳过下面这部分。vue

源码目录设计

Vue.js 的源码都在 src 目录下,其目录结构以下。java

src
├── compiler        # 编译相关 
├── core            # 核心代码 
├── platforms       # 不一样平台的支持
├── server          # 服务端渲染
├── sfc             # .vue 文件解析
├── shared          # 共享代码

复制代码

compiler

compiler 目录包含 Vue.js 全部编译相关的代码。它包括把模板解析成 AST 语法树,AST语法树优化,代码生成等功能。react

编译的工做能够在构建时作(能够借助 webpack、vue-loader 等插件);也能够在运行时作,使用包含构建功能的 Vue.js。编译是一项耗性能的工做,因此更推荐前者——离线编译。webpack

core

core 目录包含了 Vue.js 的核心代码,包括有内置组件、全局 API 封装,Vue 实例化、Obsever、Virtual DOM、工具函数 Util 等等。git

platform

Vue.js 是一个跨平台的 MVVM 框架,它能够跑在 web 上,也能够配合 weex 跑在 native 客户端上。platform 是 Vue.js 的入口,2 个目录表明 2 个主要入口,分别打包成运行在 web 上和 weex 上的 Vue.js。github

server

Vue.js 2.0 支持了服务端渲染,全部服务端渲染相关的逻辑都在这个目录下。注意:这部分代码是跑在服务端的 Node.js,不要和跑在浏览器端的 Vue.js 混为一谈。web

服务端渲染主要的工做是把组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将静态标记"混合"为客户端上彻底交互的应用程序。编程

sfc

一般咱们开发 Vue.js 都会借助 webpack 构建, 而后经过 .vue 单文件来编写组件。json

这个目录下的代码逻辑会把 .vue 文件内容解析成一个 JavaScript 的对象。

shared

Vue.js 会定义一些工具方法,这里定义的工具方法都是会被浏览器端的 Vue.js 和服务端的 Vue.js 所共享的。

接下来咱们来找一下Vue的入口文件,咱们接下来的分析都是基于platform为web的环境下进行的分析,从 package.json 和 config的 的打包配置中里能够看出,运行在web环境 (Runtime only (CommonJS))的入口文件在 web/entry-runtime.js下。

Vue入口文件

Vue入口文件目录 vue/src/core/instance/index.js

// vue/src/core/instance/index.js
import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'

function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue

复制代码

采用的是ES5的写法,并非ES6的Class写法的优势,是由于:

一、使用混入Mixin的方式传入Vue,为Vue的原型prototype上增长方法。class难以实现这种方法 二、此种方式将代码模块合理划分,将扩展分散到多个模块中去实现,使得代码文件不会过于庞大,便于维护和管理。这个编程技巧之后能够用于代码开发实现中。

经过Mixin增长的原型方法:

// vue/src/core/instance/index.js
initMixin(Vue) // _init
stateMixin(Vue) // $set$delete$watch
eventsMixin(Vue) // $on$once$off$emit
lifecycleMixin(Vue) // _update、$forceUpdate$destroy、
renderMixin(Vue) // $nextTick、_render 


复制代码

initGlobalAPI

在 vue/src/core/index.js 中,调用的initGlobalAPI(Vue),是为Vue增长静态方法的,

在路径 vue/src/core/global-api/ 目录下的文件中,都是给Vue添加的静态方法

好比:

Vue.use // 使用plugin
Vue.extend
Vue.mixin 
Vue.component 
Vue.directive 
Vue.filter

复制代码

有了这些基础的了解和一步步的跟踪查找后,咱们一步一步找到了 new Vue 所在的位置,接下来咱们来看下 new Vue 到底作了什么?

new Vue 作了什么

从入口的文件看来,经过new关键字初始化,调用了

// src/core/instance/index.js

this._init(options)

复制代码

而后从Mixin增长的原型方法看,initMixin(Vue),调用的是为Vue增长的原型方法_init

// src/core/instance/init.js

Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    ....
    ....
    // expose real self
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')
    
    ....
    ....
    
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
}


复制代码

因此,从上面的函数看来,new vue所作的事情,就像一个流程图同样展开了,分别是

  • 合并配置
  • 初始化生命周期
  • 初始化事件中心
  • 初始化渲染
  • 调用 beforeCreate 钩子函数
  • init injections and reactivity(这个阶段属性都已注入绑定,并且被 $watch 变成reactivity,可是 $el 仍是没有生成,也就是DOM没有生成)
  • 初始化state状态(初始化了data、props、computed、watcher)
  • 调用created钩子函数。

在初始化的最后,检测到若是有 el 属性,则调用 vm.$mount 方法挂载 vm,挂载的目标就是把模板渲染成最终的 DOM。

Vue代码初始化的主线逻辑很是分明,使得逻辑和流程很是清楚,这种编程方法值得学习。

最后

如今的部分只是粗略的函数上讲了 new Vue 的过程和含义,接下来的文档会继续对Vue的源码进行学习和分析,会接着更细地分析在生命周期lifecyle下每个函数后面具体所作的事情。

相关文章
相关标签/搜索