作用
使用基础的vue 构造器,创建一个子类。参数是包含组件选项的对象。其中data 必须是函数
使用场景
1、所有自定义组件都是通过extend 方法构造出来的
2、实现js调用组件,element-ui 的Message ,MessageBox 等js调用组件,都是通过Vue.extend 实现的
原理分析
1、获取父类的cid
2、从对象参数中获取缓存池,根据父类的cid 判断缓存池中是否已经在之前创建过改子类。是,就直接返回缓存的。这是为了vue 的性能考虑的。对于同一个组件选项对象,反复调用vue.extend 返回的是同一个结果的
3、获取组件的 name 字段,校验组件名字是否合法
4、通过函数的方式创建一个sub 类,并将父类的原型链继承到子类中(原型链继承方式),同时还需要修正constructor 的指向
5、将父类的options 字段和传入组件对象选项进行合并,并保存在子类sub 的options 字段中
6、将父类保存到子类的 super 字段中,确保子类能拿到父类
7、初始化props ,实际上是代理到_props 属性。根组件的 props 是在这里进行数据劫持的。好处就是不用为每个组件的实例都做一层 proxy,这是一种优化手段
8、初始化computed
9、将父类的extend ,mixin 等全局 API 添加到子类中
10、如果name 字段存在,则给子类sub 添加name 字段,方便进行组件递归
11、新增superOptions ,extendOptions 等子类独有的属性
12、将构造出来的子类sub 放进缓存池,key 值为父类的cid
13、返回子类sub
源码
源码位于src/core/global-api/extend.js
import { ASSET_TYPES } from 'shared/constants'
import { defineComputed, proxy } from '../instance/state'
import { extend, mergeOptions, validateComponentName } from '../util/index'
export function initExtend (Vue: GlobalAPI) {
Vue.cid = 0
let cid = 1
Vue.extend = function (extendOptions: Object): Function {
extendOptions = extendOptions || {}
const Super = this
const SuperId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId]
}
const name = extendOptions.name || Super.options.name
if (process.env.NODE_ENV !== 'production' && name) {
validateComponentName(name)
}
const Sub = function VueComponent (options) {
this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Sub.cid = cid++
Sub.options = mergeOptions(
Super.options,
extendOptions
)
Sub['super'] = Super
if (Sub.options.props) {
initProps(Sub)
}
if (Sub.options.computed) {
initComputed(Sub)
}
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type]
})
if (name) {
Sub.options.components[name] = Sub
}
Sub.superOptions = Super.options
Sub.extendOptions = extendOptions
Sub.sealedOptions = extend({}, Sub.options)
cachedCtors[SuperId] = Sub
return Sub
}
}
function initProps (Comp) {
const props = Comp.options.props
for (const key in props) {
proxy(Comp.prototype, `_props`, key)
}
}
function initComputed (Comp) {
const computed = Comp.options.computed
for (const key in computed) {
defineComputed(Comp.prototype, key, computed[key])
}
}
|