mirror of
https://gitee.com/vuejs/vue.git
synced 2024-12-02 12:07:39 +08:00
better global mixin strategy
This commit is contained in:
parent
1d88d9b8a0
commit
1d8f3a264e
@ -8,6 +8,9 @@ declare interface Component {
|
||||
static options: Object;
|
||||
// extend
|
||||
static extend: (options: Object) => Function;
|
||||
static superOptions: Object;
|
||||
static extendOptions: Object;
|
||||
static super: Class<Component>;
|
||||
// assets
|
||||
static directive: (id: string, def?: Function | Object) => Function | Object | void;
|
||||
static component: (id: string, def?: Class<Component> | Object) => Class<Component>;
|
||||
|
@ -18,8 +18,7 @@ export type Config = {
|
||||
_assetTypes: Array<string>,
|
||||
_lifecycleHooks: Array<string>,
|
||||
_maxUpdateCount: number,
|
||||
_isServer: boolean,
|
||||
_ctors: Array<Function>
|
||||
_isServer: boolean
|
||||
}
|
||||
|
||||
const config: Config = {
|
||||
@ -105,14 +104,7 @@ const config: Config = {
|
||||
/**
|
||||
* Server rendering?
|
||||
*/
|
||||
_isServer: process.env.VUE_ENV === 'server',
|
||||
|
||||
/**
|
||||
* Keeping track of all extended Component constructors
|
||||
* so that we can update them in the case of global mixins being applied
|
||||
* after their creation.
|
||||
*/
|
||||
_ctors: []
|
||||
_isServer: process.env.VUE_ENV === 'server'
|
||||
}
|
||||
|
||||
export default config
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* @flow */
|
||||
|
||||
import config from '../config'
|
||||
import { warn, remove, mergeOptions } from '../util/index'
|
||||
import { warn, mergeOptions } from '../util/index'
|
||||
|
||||
export function initExtend (Vue: GlobalAPI) {
|
||||
/**
|
||||
@ -54,12 +54,11 @@ export function initExtend (Vue: GlobalAPI) {
|
||||
if (name) {
|
||||
Sub.options.components[name] = Sub
|
||||
}
|
||||
// book-keeping for global mixin edge cases. also expose a way to remove it
|
||||
// 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
|
||||
config._ctors.push(Sub)
|
||||
Sub.release = () => {
|
||||
remove(config._ctors, Sub)
|
||||
}
|
||||
// cache constructor
|
||||
if (isFirstExtend) {
|
||||
extendOptions._Ctor = Sub
|
||||
|
@ -1,17 +1,9 @@
|
||||
/* @flow */
|
||||
|
||||
import config from '../config'
|
||||
import { mergeOptions } from '../util/index'
|
||||
|
||||
export function initMixin (Vue: GlobalAPI) {
|
||||
Vue.mixin = function (mixin: Object) {
|
||||
Vue.options = mergeOptions(Vue.options, mixin)
|
||||
// update constructors that are already created
|
||||
config._ctors.forEach(Ctor => {
|
||||
Ctor.options = mergeOptions(Ctor['super'].options, Ctor.extendOptions)
|
||||
if (Ctor.options.name) {
|
||||
Ctor.options.components[Ctor.options.name] = Ctor
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ export function initMixin (Vue: Class<Component>) {
|
||||
initInternalComponent(vm, options)
|
||||
} else {
|
||||
vm.$options = mergeOptions(
|
||||
vm.constructor.options,
|
||||
resolveConstructorOptions(vm),
|
||||
options || {},
|
||||
vm
|
||||
)
|
||||
@ -44,19 +44,37 @@ export function initMixin (Vue: Class<Component>) {
|
||||
callHook(vm, 'created')
|
||||
initRender(vm)
|
||||
}
|
||||
}
|
||||
|
||||
function initInternalComponent (vm: Component, options: InternalComponentOptions) {
|
||||
const opts = vm.$options = Object.create(vm.constructor.options)
|
||||
// doing this because it's faster than dynamic enumeration.
|
||||
opts.parent = options.parent
|
||||
opts.propsData = options.propsData
|
||||
opts._parentVnode = options._parentVnode
|
||||
opts._parentListeners = options._parentListeners
|
||||
opts._renderChildren = options._renderChildren
|
||||
opts._componentTag = options._componentTag
|
||||
if (options.render) {
|
||||
opts.render = options.render
|
||||
opts.staticRenderFns = options.staticRenderFns
|
||||
function initInternalComponent (vm: Component, options: InternalComponentOptions) {
|
||||
const opts = vm.$options = Object.create(resolveConstructorOptions(vm))
|
||||
// doing this because it's faster than dynamic enumeration.
|
||||
opts.parent = options.parent
|
||||
opts.propsData = options.propsData
|
||||
opts._parentVnode = options._parentVnode
|
||||
opts._parentListeners = options._parentListeners
|
||||
opts._renderChildren = options._renderChildren
|
||||
opts._componentTag = options._componentTag
|
||||
if (options.render) {
|
||||
opts.render = options.render
|
||||
opts.staticRenderFns = options.staticRenderFns
|
||||
}
|
||||
}
|
||||
|
||||
function resolveConstructorOptions (vm: Component) {
|
||||
const Ctor = vm.constructor
|
||||
let options = Ctor.options
|
||||
if (Ctor.super) {
|
||||
const superOptions = Ctor.super.options
|
||||
const cachedSuperOptions = Ctor.superOptions
|
||||
if (superOptions !== cachedSuperOptions) {
|
||||
// super option changed
|
||||
Ctor.superOptions = superOptions
|
||||
options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
|
||||
if (options.name) {
|
||||
options.components[options.name] = Ctor
|
||||
}
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
}
|
||||
|
@ -35,11 +35,4 @@ describe('Global API: mixin', () => {
|
||||
})
|
||||
expect(calls).toEqual(['hello global', 'hello local'])
|
||||
})
|
||||
|
||||
it('should allow releasing constructors', () => {
|
||||
const Test = Vue.extend({})
|
||||
expect(Vue.config._ctors.indexOf(Test) > -1).toBe(true)
|
||||
Test.release()
|
||||
expect(Vue.config._ctors.indexOf(Test) > -1).toBe(false)
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user