]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat: support initializers in mixins
authorEvan You <yyx990803@gmail.com>
Wed, 17 Oct 2018 00:04:58 +0000 (20:04 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 17 Oct 2018 00:04:58 +0000 (20:04 -0400)
packages/core/src/component.ts
packages/core/src/componentState.ts
packages/core/src/optional/mixin.ts

index 34631eec68a92c2a98937e464fc4f8294da0faa7..dbe4d8e457f4b1f39509c5df6b579fcbdb0a1e22 100644 (file)
@@ -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
index 594d8b3d3c0e63d65a64763d6a0c904805419866..7e74bb1a4b2a6400c2252c2c9dd0d9100561e95f 100644 (file)
@@ -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
 }
index f6de28616642151e96a321446b27a67e2db48561..cf2b2c09b54dfc37ffe69ba340d5656436017ad0 100644 (file)
@@ -6,6 +6,7 @@ import {
   mergeComponentOptions
 } from '../componentOptions'
 import { normalizePropsOptions } from '../componentProps'
+import { extractInitializers } from '../componentState'
 import { isFunction } from '@vue/shared'
 
 interface ComponentConstructor<This = Component> {
@@ -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)
 }