ソースを参照

fix global mixin props (fix #3957)

Evan You 9 年 前
コミット
cb1bb75b58

+ 27 - 28
src/core/instance/init.js

@@ -24,7 +24,7 @@ export function initMixin (Vue: Class<Component>) {
       initInternalComponent(vm, options)
     } else {
       vm.$options = mergeOptions(
-        resolveConstructorOptions(vm),
+        resolveConstructorOptions(vm.constructor),
         options || {},
         vm
       )
@@ -44,37 +44,36 @@ export function initMixin (Vue: Class<Component>) {
     callHook(vm, 'created')
     initRender(vm)
   }
+}
 
-  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 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 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
-        }
+export function resolveConstructorOptions (Ctor: Class<Component>) {
+  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
   }
+  return options
 }

+ 5 - 0
src/core/vdom/create-component.js

@@ -3,6 +3,7 @@
 import Vue from '../instance/index'
 import VNode from './vnode'
 import { normalizeChildren } from './helpers/index'
+import { resolveConstructorOptions } from '../instance/init'
 import { activeInstance, callHook } from '../instance/lifecycle'
 import { resolveSlots } from '../instance/render'
 import { createElement } from './create-element'
@@ -33,6 +34,10 @@ export function createComponent (
     return
   }
 
+  // resolve constructor options in case global mixins are applied after
+  // component constructor creation
+  resolveConstructorOptions(Ctor)
+
   // async component
   if (!Ctor.cid) {
     if (Ctor.resolved) {

+ 19 - 0
test/unit/features/global-api/mixin.spec.js

@@ -37,4 +37,23 @@ describe('Global API: mixin', () => {
     })
     expect(calls).toEqual(['hello global', 'hello local'])
   })
+
+  // #3957
+  it('should work for global props', () => {
+    const Test = Vue.extend({
+      template: `<div>{{ prop }}</div>`
+    })
+
+    Vue.mixin({
+      props: ['prop']
+    })
+
+    // test child component
+    const vm = new Vue({
+      template: '<test prop="hi"></test>',
+      components: { Test }
+    }).$mount()
+
+    expect(vm.$el.textContent).toBe('hi')
+  })
 })