From: Evan You Date: Wed, 17 Oct 2018 00:04:58 +0000 (-0400) Subject: feat: support initializers in mixins X-Git-Tag: v3.0.0-alpha.0~1099 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7ce16ea8d66e4ce6c05deb5052f0066c446b9eae;p=thirdparty%2Fvuejs%2Fcore.git feat: support initializers in mixins --- diff --git a/packages/core/src/component.ts b/packages/core/src/component.ts index 34631eec68..dbe4d8e457 100644 --- a/packages/core/src/component.ts +++ b/packages/core/src/component.ts @@ -137,8 +137,16 @@ class InternalComponent implements PublicInstanceMethods { _isVue: boolean = true _inactiveRoot: boolean = false - constructor() { - initializeComponentInstance(this as any) + constructor(props?: object) { + if (props === void 0) { + initializeComponentInstance(this as any) + } else { + // the presence of the props argument indicates that this class is being + // instantiated as a mixin, and should expose the props on itself + // so that the extended class constructor (and property initializers) can + // access $props. + this.$props = props + } } // to be set by renderer during mount diff --git a/packages/core/src/componentState.ts b/packages/core/src/componentState.ts index 594d8b3d3c..7e74bb1a4b 100644 --- a/packages/core/src/componentState.ts +++ b/packages/core/src/componentState.ts @@ -6,12 +6,21 @@ const internalRE = /^_|^\$/ export function initializeState(instance: ComponentInstance) { const { data } = instance.$options const rawData = (instance._rawData = (data ? data.call(instance) : {}) as any) + extractInitializers(instance, rawData) + instance.$data = observable(rawData || {}) +} + +// extract properties initialized in a component's constructor +export function extractInitializers( + instance: ComponentInstance, + data: any = {} +): any { const keys = Object.keys(instance) for (let i = 0; i < keys.length; i++) { const key = keys[i] if (!internalRE.test(key)) { - rawData[key] = (instance as any)[key] + data[key] = (instance as any)[key] } } - instance.$data = observable(rawData || {}) + return data } diff --git a/packages/core/src/optional/mixin.ts b/packages/core/src/optional/mixin.ts index f6de286166..cf2b2c09b5 100644 --- a/packages/core/src/optional/mixin.ts +++ b/packages/core/src/optional/mixin.ts @@ -6,6 +6,7 @@ import { mergeComponentOptions } from '../componentOptions' import { normalizePropsOptions } from '../componentProps' +import { extractInitializers } from '../componentState' import { isFunction } from '@vue/shared' interface ComponentConstructor { @@ -36,14 +37,25 @@ export function mixins(...args: any[]): any { let options: ComponentOptions = {} args.forEach(mixin => { if (isFunction(mixin)) { - options = mergeComponentOptions( - options, - resolveComponentOptionsFromClass(mixin) - ) + const Class = mixin + mixin = resolveComponentOptionsFromClass(Class) + // in order to extract properties initialized in the mixin's constructor, + // we create an instance of it and pass in the actual props - this + // short-circuits the normal component initialization and allows us to + // relatively-cheaply extract the properties added in the constructor. + function extractData() { + return extractInitializers(new Class(this.$props)) + } + const { data } = mixin + mixin.data = data + ? function() { + return Object.assign(data.call(this), extractData.call(this)) + } + : extractData } else { mixin.props = normalizePropsOptions(mixin.props) - options = mergeComponentOptions(options, mixin) } + options = mergeComponentOptions(options, mixin) }) return createComponentClassFromOptions(options) }