Vue 源码分析 —— 组件的注册方式

150 阅读3分钟

开始逐步分析 Vue 源码,个人能力有限,如有错误请各位大佬指点

组件基础

组件是 Vue 一个重要核心,在项目工程化时,会将页面结构组件化。组件化以为这独立和共享,这两个结论并不矛盾。独立的组件可以让开发者在开发组件时能够专注某个功能的开发和扩展,而组件的设计理念又使得功能更加具有复用性,不同的页面可以进行组件功能的共享。

组件的注册方式

在使用 Vue 组件之前,先要进行组件注册,在 Vue 中,组件注册分为两种,全局注册局部注册

全局注册

组件的全局注册需要在全局实例化 Vue 之前,全局注册后的组件可以在任何创建的 Vue 示例中使用

Vue.component("component-name", {
  template: "<div>{{test}}</div>",
  data(){
    return {
      test: "component-test"
    }
  }
})

局部注册

当某个组件只需要在局部使用时,可以使用局部注册的方式注册组件。局部注册的组件只能在注册该组件的内部使用

var myTest = {
  template: '<div>{{test}}</div>',
  data () {
    return {
        test: 1212
    }
  }
}
var vm = new Vue({
  el: '#app',
  components: {
      myTest
  }
})

注册过程

全局注册

我们来看下组件注册的过程,以全局注册为例, 它通过 Vue.component(name, {...}) 进行组件注册。 Vue.component 是在 Vue 引入阶段定义的静态方法。在初始化全局 API 时执行 initAssetRegisters 来定义 Vue.component 方法

// 定义 Vue.component 、 Vue.filter 、 Vue.directive 等方法
initAssetRegisters()

const ASSET_TYPES = [
  'component',
  'directive',
  'filter'
]

function initAssetRegisters (Vue: GlobalAPI) {
  /**
   * 定义一些静态方法
   */
  ASSET_TYPES.forEach(type => {
    Vue[type] = function (
      id: string,
      definition: Function | Object
    ): Function | Object | void {
      if (!definition) {
        return this.options[type + 's'][id]
      } else {
        // 校验组件名的合法性
        if (process.env.NODE_ENV !== 'production' && type === 'component') {
          validateComponentName(id)
        }
        if (type === 'component' && isPlainObject(definition)) {
          // 注册组件时,第二个参数时一个普通对象时, 通过  Vue.extend 方法创建子组件并返回子类构造器
          definition.name = definition.name || id
          definition = this.options._base.extend(definition)
        }
        if (type === 'directive' && typeof definition === 'function') {
          definition = { bind: definition, update: definition }
        }
        // 为 Vue.options 上的对应属性添加子类构造器
        this.options[type + 's'][id] = definition
        return definition
      }
    }
  })
}

全局注册组件时,首先会校验组件名称的合法行,然后通过 extend 方法创建一个子类构造器, 并将子类构造器添加到 Vue 原型 options.components 对象上,键名为组件名称,值为子类构造器函数。

局部注册

局部注册组件时,是在将组件添加到某个组件的 components 选项中,此时键为组件名称, 值组件所指向(导出)的对象

var myTest = {
  template: '<div>{{test}}</div>',
  data () {
    return {
        test: 1212
    }
  }
}
var vm = new Vue({
  el: '#app',
  components: {
      myTest
  }
})

总结

  • 全局注册组件: 调用 Vue 的静态方法,通过 extend 方法生成一个子类构造器,并将子类构造器添加到 Vue 原型的 options.components 对象上,在 Vue 初始化合并选项过程中,会将 Vue 原型上的 options 对象合并到 Vue 根实例中, 全局注册的组件,在 vm.options.components 对象中保存的值时 子类构造器(构造函数)

  • 局部注册: 局部注册组件只需要将组件对象添加到 components 选项中即可,此时 vm.options.components 保存的值是对象