vue探究:vue component 与 extend

Vue component与Vue extend

为什么要了解vue注册组件原理

在思考表单集成方案的时候,我们知道,在配置json生成form组件的时候,总会通过type与form组件一一对应来找到对应的组件,也就是说,在声明json form类型之前,需要提前开发对应的组件,或者动态挂载组件。在vue框架下,想要做到持续集成,可以将组件声明为全局组件,然后在json转化为组件时候通过name来加载对应组件。但这样做的缺陷是,无法动态给第三方组件挂载公共的属性与事件;在设计上看,将扩展组件的功能收敛至统一入口,再借助vue动态实例化组件的能力,这样做有利于后续持续集成,减少开发上的副作用,使整个库的开发思路可控。

Vue.extend

Vue.extend(extendOptions)

通过调用vue.extend可返回一个vue的子类

function extend(extendOptions){
    extendOptions = extendOptions || {}
    // this->vue
    const Super = this
    const SuperId = Super.cid
    // 使用父类的id作为缓存的key
    // 只要父类id相同,每次调用会返回相同的子类
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) {
      return cachedCtors[SuperId]
    }   
    // 对name命名方式进行校验
    // /^[a-zA-Z][\w-]*/
    const name = extendOptions.name || Super.options.name
    if (process.env.NODE_ENV !== 'production' && name) {
      validateComponentName(name)
    }

    const Sub = function VueComponent (options) {
      // vue._init
      this._init(options)
    }
    // 继承父类构造函数
    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    // 合并父类的options
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    Sub['super'] = Super

    // For props and computed properties, we define the proxy getters on
    // the Vue instances at extension time, on the extended prototype. This
    // avoids Object.defineProperty calls for each instance created.
    // 初始化props
    // 将props挂载在原型对象的_props属性下
    if (Sub.options.props) {
      initProps(Sub)
    }
    // 初始化computed
    // 将初始化computed挂载在原型对象下
    if (Sub.options.computed) {
      initComputed(Sub)
    }

    // allow further extension/mixin/plugin usage
    // 复制父类的静态方法
    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use

    // create asset registers, so extended classes
    // can have their private assets too.
    ASSET_TYPES.forEach(function (type) {
      Sub[type] = Super[type]
    })
    // enable recursive self-lookup
    if (name) {
      Sub.options.components[name] = Sub
    }

    // keep a reference to the super options at extension time.
    // later at instantiation we can check if Super's options have
    // been updated.
    Sub.superOptions = Super.options
    Sub.extendOptions = extendOptions
    Sub.sealedOptions = extend({}, Sub.options)

    // cache constructor
    cachedCtors[SuperId] = Sub
    return Sub
  }
}
复制代码

首先,同直接调用vue构造函数实例化组件来对比,vue.extend在开始先做来一层缓存校验,如果该extendOptions已经存在组件的构造函数,那么会直接返回该构造函数,避免同一个组件反复构建组件生成器函数,同时使用父类的id作为缓存标时。

当未命中缓存时,会进入创建组件生成器函数的过程,首先对组件名称进行校验,名称首字母开头必须是大小写英文,后续字符支持大小写下划线(_)及间隔线(-)。

名称校验通过后,先声明一个组件对构造函数:

const Sub = function VueComponent (options) {
  // Vue.prototype._init
  this._init(options)
}
复制代码

让Sub函数通过原型继承父类(Vue),并将传入的extendOptions与父类的options配置项进行合并,然后保存父类的构造函数至super属性。

options中挂载propscomputed等属性时,需要单独进行处理,处理的内部细节与结果在后续的vue探究文章再做深入讨论。

当通过原型继承父类,初始化propscomputed成员属性之后,还需要继承父类的静态方法,如mixin、extend、use、component、directive、filter等。

最后在子类构造函数上新增superOptions、extendOptions、sealedOptions以备实例化的时候使用,再缓存该新生成子类(组件构造函数)。

总的来看,vue.extend方法本质是创建了一个Sub函数,并继承了父类(父组件或者Vue构造函数)的相关属性或者方法。

Vue.component

调用component注册一个局部或者全局组件,并设置组件的别名。

// 在Vue中,component、filter、directive是混合在一起实现的,这里拆开
Vue.options['component'] = Object.create(null)

Vue.component = function(id, definition){
    if(!definition){
        return this.options['components'][id]
    }else{
        if(isPlainObject(definition)){
            definition.name = definition.name || id
            definition = Vue.extend(definition)
        }
        this.options['components'][id] = definition
        return definition
    }
}
复制代码

component方法本质是调用extend方法构造一个子类,并将该子类保存在options的components的对应的key下面,在SFC中注册的。

文章内容如有错误,敬请谅解,希望可以不吝赐教

转载请注明出处

转载于:https://juejin.im/post/5cf7a951f265da1b83337c86

猜你喜欢

转载自blog.csdn.net/weixin_33912453/article/details/91420323
今日推荐