美文网首页
Vue源码学习(二)之 找到Vue

Vue源码学习(二)之 找到Vue

作者: Love小六六 | 来源:发表于2019-08-21 00:43 被阅读0次

    寻找 Vue 的入口

    • src/platforms/web/entry-runtime-with-compiler 文件,它虽然export default Vue ,但是先从./runtime/index import 了 Vue
    import Vue from './runtime/index'
    
    • runtime/indexcore/index中 import 了 Vue
    import Vue from 'core/index'
    
    • core/indexinstance/index中 import Vue ,并初始化全局 API ,给 Vue 这个对象本身扩展全局的静态方法
    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)
    
    • instance/index 中我们会发现, Vue实际上是一个 Function 实现的类,我们只能通过 new Vue 去实例化它,为什么不用 class 来定义 Vue 呢

    因为有很多 xxxMixin 的函数调用,把 Vue 当参数传入,它们的功能都是给 Vue 的 prototype 上扩展一些方法,Vue 按功能把这些扩展分散到多个模块中去实现,而不是在一个模块里实现所有,这种方式是用 Class 难以实现的。这么做的好处是非常方便代码的维护和管理

    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
    
    • 这样一来我们就找到了 Vue 的入口
    • 那么一系列的 mixin 函数又做了什么呢,我在下面做了个总结
    // initMixin(Vue)    src/core/instance/init.js **************************************************
    Vue.prototype._init = function (options?: Object) {}
    
    // stateMixin(Vue)    src/core/instance/state.js **************************************************
    Vue.prototype.$data
    Vue.prototype.$set = set
    Vue.prototype.$delete = del
    Vue.prototype.$watch = function(){}
    
    // renderMixin(Vue)    src/core/instance/render.js **************************************************
    Vue.prototype.$nextTick = function (fn: Function) {}
    Vue.prototype._render = function (): VNode {}
    Vue.prototype._s = _toString
    Vue.prototype._v = createTextVNode
    Vue.prototype._n = toNumber
    Vue.prototype._e = createEmptyVNode
    Vue.prototype._q = looseEqual
    Vue.prototype._i = looseIndexOf
    Vue.prototype._m = function(){}
    Vue.prototype._o = function(){}
    Vue.prototype._f = function resolveFilter (id) {}
    Vue.prototype._l = function(){}
    Vue.prototype._t = function(){}
    Vue.prototype._b = function(){}
    Vue.prototype._k = function(){}
    
    // eventsMixin(Vue)    src/core/instance/events.js **************************************************
    Vue.prototype.$on = function (event: string, fn: Function): Component {}
    Vue.prototype.$once = function (event: string, fn: Function): Component {}
    Vue.prototype.$off = function (event?: string, fn?: Function): Component {}
    Vue.prototype.$emit = function (event: string): Component {}
    
    // lifecycleMixin(Vue)    src/core/instance/lifecycle.js **************************************************
    Vue.prototype._mount = function(){}
    Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {}
    Vue.prototype._updateFromParent = function(){}
    Vue.prototype.$forceUpdate = function () {}
    Vue.prototype.$destroy = function () {}
    
    • 知道了 Vue 的构造函数以及一系列的 mixin 做了什么之后 ,我们在回溯到上一个,及core/index.js
    initGlobalAPI(Vue)
    
    • initGlobalAPI 的作用是在 Vue 构造函数上挂载静态属性和方法,经历过initGlobalAPI 后 Vue 如下
    Vue.config
    Vue.util = util
    Vue.set = set
    Vue.delete = del
    Vue.nextTick = util.nextTick
    Vue.observable
    Vue.options = {
        components: {
            KeepAlive
        },
        directives: {},
        filters: {},
        _base: Vue
    }
    Vue.use
    Vue.mixin
    Vue.cid = 0
    Vue.extend
    Vue.component = function(){}
    Vue.directive = function(){}
    Vue.filter = function(){}
    
    • 继续回溯,在platforms/web/runtime.js中主要做了三件事

    一、覆盖 Vue.config 的属性,将其设置为平台特有的一些方法

    二、Vue.options.directives 和 Vue.options.components 安装平台特有的指令和组件

    三、在 Vue.prototype 上定义 _patch_ 和 $mount

    • 这个时候的 Vue 又增加了新的属性
    // 安装平台特定的utils
    Vue.config.isUnknownElement = isUnknownElement
    Vue.config.isReservedTag = isReservedTag
    Vue.config.getTagNamespace = getTagNamespace
    Vue.config.mustUseProp = mustUseProp
    // 安装平台特定的 指令 和 组件
    Vue.options = {
        components: {
            KeepAlive,
            Transition,
            TransitionGroup
        },
        directives: {
            model,
            show
        },
        filters: {},
        _base: Vue
    }
    Vue.prototype.__patch__
    Vue.prototype.$mount
    
    • 最后我们回溯到了``entry-runtime-with-compiler````文件中,这个文件重要做了两件事

    1、缓存来自 web-runtime.js 文件的 $mount 函数, const mount = Vue.prototype.$mount然后覆盖覆盖了 Vue.prototype.$mount

    2、在 Vue 上挂载 compile Vue.compile = compileToFunctions,
    compileToFunctions 函数的作用,就是将模板 template 编译为 render 函数

    总结

    • 至此我们将 Vue 构造函数做了简单的一轮梳理

    Vue.prototype 下的属性和方法的挂载主要是在 src/core/instance 目录中的代码处理的

    Vue 下的静态属性和方法的挂载主要是在src/core/global-api 目录下的代码处理的

    platforms/web/runtime/index.js 主要是添加 web 平台特有的配置、组件和指令,entry-runtime-with-compiler.js 给 Vue 的 $mount 方法添加 compiler 编译器,支持 template。

    相关文章

      网友评论

          本文标题:Vue源码学习(二)之 找到Vue

          本文链接:https://www.haomeiwen.com/subject/xmhvsctx.html