资讯专栏INFORMATION COLUMN

人人都能懂的Vue源码系列—03—resolveConstructorOptions函数-上

snifes / 504人阅读

摘要:上篇文章介绍了构造函数的部分实现,当前实例不是组件时,会执行方法。这个文件就是对构造函数进行的第一层包装了。但是注意这里的代码我们构造函数的第二层包装,就在这个文件里了。回到的源码中,当不存在时,直接返回基础构造器的。

上篇文章介绍了Vue构造函数的部分实现,当前Vue实例不是组件时,会执行mergeOptions方法。

vm.$options = mergeOptions(
  resolveConstructorOptions(vm.constructor),
    options || {},
    vm
)

mergeOptions方法,我们之后的博文再来做详细介绍。今天主要研究resolveConstructorOptions方法,从字面意思来看,这个方法是来解析constructor上的options属性的。我们来看源码。

export function resolveConstructorOptions (Ctor: Class) {
  let options = Ctor.options
  // 有super属性,说明Ctor是Vue.extend构建的子类
  if (Ctor.super) {
    const superOptions = resolveConstructorOptions(Ctor.super)
    const cachedSuperOptions = Ctor.superOptions // Vue构造函数上的options,如directives,filters,....
    if (superOptions !== cachedSuperOptions) {
      // super option changed,
      // need to resolve new options.
      Ctor.superOptions = superOptions
      // check if there are any late-modified/attached options (#4976)
      const modifiedOptions = resolveModifiedOptions(Ctor)
      // update base extend options
      if (modifiedOptions) {
        extend(Ctor.extendOptions, modifiedOptions)
      }
      options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
      if (options.name) {
        options.components[options.name] = Ctor
      }
    }
  }
  return options
}

这个方法要分成两种情况来说明,第一种是Ctor是基础Vue构造器的情况,另一种是Ctor是通过Vue.extend方法扩展的情况。

Ctor是基础Vue构造器

当Ctor(Ctor其实就是构造函数)是基础Vue构造器时,比如是通过new关键字新建Vue构造函数的实例

const vm = new Vue({
  el: "#app",
    data: {
      message: "Hello Chris"
    }
})

这个时候options就是Vue构造函数上的options。如下图

那么这个options是在哪里定义的呢?在之前的代码中好像没有看到options的定义在哪里?此时我们应该怎么去找这个options定义的地方呢?
这里教大家一个方法,首先找到package.json,在这里可以找到我们平时用到的一些npm脚本。以npm run dev为例。实际上npm run dev是执行了下列的命令
"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev"
rollup是类似于webpack的打包工具。我们可以看到这条命令指向了一个地址scripts/config,之后还指定了一个Target。找到script/config,发现这个文件里
有TARGET为web-full-dev的配置。

// Runtime+compiler development build (Browser)
  "web-full-dev": {
    entry: resolve("web/entry-runtime-with-compiler.js"),
    dest: resolve("dist/vue.js"),
    format: "umd",
    env: "development",
    alias: { he: "./entity-decoder" },
    banner
  }

来分析上面的代码,入口文件的地址在web/entry-runtime-with-compiler.js。这个文件就是对Vue构造函数进行的第一层包装了。由于今天分析的是options相关的内容,而这层包装里没有options相关的内容,所以这个文件我们不展开讲(之后有文章会详细介绍)。但是注意这里的代码

...
import Vue from "./runtime/index"
...

我们Vue构造函数的第二层包装,就在这个文件里了。忽略其他的代码,我们来看关于Vue.options的部分

...
import Vue from "core/index" // 第三层包装
import platformDirectives from "./directives/index"
import platformComponents from "./components/index"
...
// install platform runtime directives & components
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)
...

// platformDirectives相关
// 这里导出Vue全局指令model,show
import model from "./model"
import show from "./show"
export default {
  model,
  show
}

// platformComponents相关
// 这里导出Vue全局组件Transition,TransitionGroup
import Transition from "./transition"
import TransitionGroup from "./transition-group"
export default {
  Transition,
  TransitionGroup
}

上面的代码主要是给Vue.options.directives添加model,show属性,给Vue.options.components添加Transition,TransitionGroup属性。那么还有filters,_base属性,以及components中的KeepAlive又是怎么来的呢?
这就要看Vue的第三层包装里都做了些什么?找到core/index,同样我们只看Vue.options相关代码。

mport Vue from "./instance/index"
import { initGlobalAPI } from "./global-api/index"
...
initGlobalAPI(Vue)
...

instance/index 就是我们第二篇文章——构造函数定义的那个文件。这个文件我们之前看过,没有和Vue构造函数options相关的代码。那么我们剩下的没有配置的options一定是在initGlobalAPI上配置了。接来下看看/global-api/index的代码。

/* @flow */

import { ASSET_TYPES } from "shared/constants"
...
export function initGlobalAPI (Vue: GlobalAPI) {
  ...
  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(type => {
    Vue.options[type + "s"] = Object.create(null)
  })
  Vue.options._base = Vue
  extend(Vue.options.components, builtInComponents)
  ...
}

// shared/constants.js
export const ASSET_TYPES = [
  "component",
  "directive",
  "filter"
]

// core/components/index
import KeepAlive from "./keep-alive"
export default {
  KeepAlive
}

上面这层包装就把filters,_base和components中的KeepAlive都实现了。通过这三层包装,Vue构造函数的options对象就生成了,看这些文字可能有点绕,我们直接上图。


回到resolveConstructorOptions的源码中,当Ctor.super不存在时,直接返回基础构造器的options。即上图经过两次包装的options。那么Ctor.super是什么呢?
Ctor.super是通过Vue.extend构造子类的时候。Vue.extend方法会为Ctor添加一个super属性,指向其父类构造器

Vue.extend = function (extendOptions: Object): Function {
  ...
  Sub["super"] = Super
  ...
}

所以当Ctor时基础构造器的时候,resolveConstructorOptions方法返回基础构造器的options。除了Ctor是基础构造器之外,还有一种是Ctor是通过Vue.extend构造的子类。这种情况比较复杂,下一篇文章专门对其进行介绍,敬请期待!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94597.html

相关文章

  • 人人都能懂的Vue源码系列—04—resolveConstructorOptions函数-下

    摘要:上一篇文章中说道,函数要分两种情况进行说明,第一种是为基础构造器的情况,这个已经向大家介绍过了,今天这篇文章主要介绍第二种情况,是创建的子类。表示的是当前构造器上新增的,表示的是当前构造器上新增的封装。 上一篇文章中说道,resolveConstructorOptions函数要分两种情况进行说明,第一种是Ctor为基础构造器的情况,这个已经向大家介绍过了,今天这篇文章主要介绍第二种情况...

    My_Oh_My 评论0 收藏0
  • 人人都能懂的Vue源码系列—04—resolveConstructorOptions函数-下

    摘要:上一篇文章中说道,函数要分两种情况进行说明,第一种是为基础构造器的情况,这个已经向大家介绍过了,今天这篇文章主要介绍第二种情况,是创建的子类。表示的是当前构造器上新增的,表示的是当前构造器上新增的封装。 上一篇文章中说道,resolveConstructorOptions函数要分两种情况进行说明,第一种是Ctor为基础构造器的情况,这个已经向大家介绍过了,今天这篇文章主要介绍第二种情况...

    BlackHole1 评论0 收藏0
  • 人人都能懂的Vue源码系列—02—Vue构造函数

    摘要:果然我们找到了的构造函数定义。告诉你是一个构造函数,需要用操作符去调用。在深入方法之前,我们先把目光移到文件里在的构造函数定义之后,有一系列方法会被立即调用。下篇博文主要介绍相关的内容,涉及到原型链和构造函数以及部分的实现,敬请期待 上篇博文中说到了Vue源码的目录结构是什么样的,每个目录的作用我们应该也有所了解。我们知道core/instance目录主要是用来实例化Vue对象,所以我...

    X_AirDu 评论0 收藏0
  • 人人都能懂的Vue源码系列—05—mergeOptions-

    摘要:在解析完其构造函数上的之后,需要把构造函数上的和实例化时传入的进行合并操作并生成一个新的。检查组件名称是否合法首先看传入的三个参数,,这三个参数分别代表的是该实例构造函数上的实例化时传入的实例本身。 前几篇文章中我们讲到了resolveConstructorOptions,它的主要功能是解析当前实例构造函数上的options,不太明白的同学们可以看本系列的前几篇文章。在解析完其构造函数...

    iKcamp 评论0 收藏0
  • 人人都能懂的Vue源码系列—01—Vue源码目录结构

    摘要:阅读的源码,或者说阅读一个框架的源码,了解它的目录结构都是很有帮助的。人人都能懂的源码系列文章将会详细的介绍源码的方方面面。 阅读Vue的源码,或者说阅读一个框架的源码,了解它的目录结构都是很有帮助的。下面我们来看看Vue源码的目录结构。showImg(https://segmentfault.com/img/bV8fLS?w=598&h=654); Vue各目录简介 下图是Vue各个...

    MAX_zuo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<