在思考表单集成方案的时候,咱们知道,在配置json生成form组件的时候,总会经过type与form组件一一对应来找到对应的组件,也就是说,在声明json form类型以前,须要提早开发对应的组件,或者动态挂载组件。在vue框架下,想要作到持续集成,能够将组件声明为全局组件,而后在json转化为组件时候经过name来加载对应组件。但这样作的缺陷是,没法动态给第三方组件挂载公共的属性与事件;在设计上看,将扩展组件的功能收敛至统一入口,再借助vue动态实例化组件的能力,这样作有利于后续持续集成,减小开发上的反作用,使整个库的开发思路可控。vue
Vue.extend(extendOptions)
json
经过调用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做为缓存标时。bash
当未命中缓存时,会进入建立组件生成器函数的过程,首先对组件名称进行校验,名称首字母开头必须是大小写英文,后续字符支持大小写下划线(_)及间隔线(-)。框架
名称校验经过后,先声明一个组件对构造函数:函数
const Sub = function VueComponent (options) {
// Vue.prototype._init
this._init(options)
}
复制代码
让Sub函数经过原型继承父类(Vue),并将传入的extendOptions
与父类的options
配置项进行合并,而后保存父类的构造函数至super
属性。ui
当options
中挂载props
与computed
等属性时,须要单独进行处理,处理的内部细节与结果在后续的vue探究
文章再作深刻讨论。this
当经过原型继承父类,初始化props
与computed
成员属性以后,还须要继承父类的静态方法,如mixin、extend、use、component、directive、filter
等。spa
最后在子类构造函数上新增superOptions、extendOptions、sealedOptions
以备实例化的时候使用,再缓存该新生成子类(组件构造函数)。prototype
总的来看,vue.extend方法本质是建立了一个Sub函数,并继承了父类(父组件或者Vue构造函数)的相关属性或者方法。
调用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
中注册的。
文章内容若有错误,敬请谅解,但愿能够不吝赐教
转载请注明出处