Vue源码剖析(一): 建立vue顺序的背地发生了什么

主要纲要:

  • 从initGlobalAPI要领看Vue.config全局设置
  • 寻根问祖-Vue的组织函数的出生地

先来一段最常见的vue代码demo

<div id="app">
  {{ message }}
</div>
// js
var vm = new Vue({
  el: '#app',
  data: {
    message: ‘hello vue'
  }
})

上面已建立了一个vue应用程序;从上面很轻易就看出来 Vue是一个组织器,vm是用这个组织器组织出来的实例化对象,实例化的时刻传入了参数,参数中包含el和data
上述延长了3个题目:

  1. Vue 组织器是什么样子容貌?
  2. Vm能够运用的要领,即vue的开放API都在源码内里怎样完成的?
  3. 我们传入组织要领内的参数发生了什么

这些题目是我们解锁vue源码的最最先的步骤,所以我们无妨经由过程vue源码的进口最先寻觅这些源码的完成

在源码的src/platforms/web下面放着差别版本的构建entry文件,这些文件中导出export的Vue,都是从src/core/instance/index这个文件import过来的,
我们先看下进口文件能带给我们什么答案:

// src/core/instance/index
import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'
initGlobalAPI(Vue)

这个进口文件做了3件事:

  1. 引用了 ./instance/index, 暴露了vue的泉源,即组织器
  2. 挪用initGlobalAPI要领,将vue传进去, 给vue拓展了全局静态要领
  3. 将vue暴露出去

这个进口文件的意义,是在暴露vue之前,给vue经由过程initGlobalAPI要领给vue拓展了全局静态要领,对应Vue的外部API是 Vue.config,包含了Vue的全局设置,

Vue.config.silent // 日记与正告
Vue.config.errorHandler // 这个处置惩罚函数被挪用的时刻,能够猎取错误信息和Vue实例
Vue.config.devtools // 设置是不是许可 vue-devtools 搜检代码
…..

从initGlobalAPI要领看Vue.config全局设置

initGlobalAPI要领定义了configDef对象,它的getter要领会的属性值是config,setter要领给出正告不许可修正。末了在vue上增加了config属性,属性形貌返回configDef对象

export function initGlobalAPI (Vue: GlobalAPI) {
    // config
    const configDef = {}
    configDef.get = () => config
    if (process.env.NODE_ENV !== 'production') {
        configDef.set = () => {
            warn(
                    'Do not replace the Vue.config object, set individual fields instead.'
                )
      }
}
Object.defineProperty(Vue, 'config', configDef) // 增加config属性

除此之外,还定义了util属性,然则并没有暴露到表面,也并不发起外部去运用

寻根问祖-Vue的组织函数的出生地

了解了组织函数,也就知道了new vue()的时刻发生了什么
下面这段代码就是Vue的组织要领,我们能够直观的看出vue组织器是运用ES5的Function去完成类,是因为能够经由过程prototype往vue原型上拓展许多要领,把这些要领拆分到差别的文件/模块下,如许更有利于代码的保护,与协同开辟
比方在这个文件中,能够看到把Vue看成一个参数传进下面的**Mixin要领中,这些要领都是经由过程吸收vue,在它的prototype上面定义一些功用的;

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’)
            //   vue必需是new vue()的实例化对象
           }
        console.log('options', options)

        this._init(options) // 挪用内部_init要领
}
initMixin(Vue) // 在created性命周期函数之前的操纵
stateMixin(Vue) // 应用 definedProperty 举行静态数据的定阅宣布
eventsMixin(Vue) // 实例事宜流的注入, 应用的是定阅宣布形式的事宜流组织
lifecycleMixin(Vue) // 
renderMixin(Vue) // 完成 _render 衬着假造dom
export default Vue

这个组织函数的最中心点,就是this._init(options)

在此处打断点,能够看到参数options传进来的就是表面我们实例化时传入的参数el 和 data

new Vue({
    el: '#app',
      data: {
        message: ‘hello vue'    
      }
})

这个_init要领出自initMixin 函数
看完这个函数,我们梳理出全部初始化阶段源码的几个主要的节点

  1. 初始化options参数举行兼并设置
  2. 初始化性命周期
  3. 初始化时候体系
  4. 初始化state,包含data、props、 computed、watcher

export function initMixin (Vue: Class<Component>) {

console.log('Vue', Vue)
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
// a uid 实例化的uid递增1
vm._uid = uid++
let startTag, endTag
/* istanbul ignore if */

// 用_isVue来标识当前的实例是个Vue实例,如许做是为了后续被observed
vm._isVue = true    
// 兼并设置options,并推断是不是是内部Component的options的初始化
if (options && options._isComponent) {
    // 内部
    initInternalComponent(vm, options)
} else {
    // 非内部
    vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
    )
}
// 在render中将this指向vm._renderProxy
if (process.env.NODE_ENV !== 'production') {
    initProxy(vm)
} else {
    vm._renderProxy = vm
}
// expose real self
vm._self = vm
// 初始化性命周期
initLifecycle(vm)    
// 初始化事宜注册
initEvents(vm)
// 初始化衬着
initRender(vm)
// 触发回掉函数中的beforeCreate钩子函数
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
// 初始化vm的状况,包含data、props、computed、watcher等
initState(vm)
initProvide(vm) // resolve provide after data/props
// vm已建立好来,回掉created钩子函数
callHook(vm, 'created’)
/* istanbul ignore if */
…
// 将实例举行挂载
if (vm.$options.el) {
    vm.$mount(vm.$options.el)
    }
}

}

    原文作者:南山
    原文地址: https://segmentfault.com/a/1190000018717391
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞