Procházet zdrojové kódy

fix #594 should merge multiple data functions in Vue.extend

Evan You před 11 roky
rodič
revize
829a610e64
2 změnil soubory, kde provedl 66 přidání a 24 odebrání
  1. 44 20
      src/util/merge-option.js
  2. 22 4
      test/unit/specs/util/merge-option_spec.js

+ 44 - 20
src/util/merge-option.js

@@ -15,40 +15,64 @@ var extend = _.extend
 
 var strats = Object.create(null)
 
+/**
+ * Helper that merges two data objects together
+ */
+
+function mergeData (to, from) {
+  for (var key in from) {
+    if (!to.hasOwnProperty(key)) {
+      to.$add(key, from[key])
+    }
+  }
+  return to
+}
+
 /**
  * Data
  */
 
 strats.data = function (parentVal, childVal, vm) {
-  // in a class merge, both should be functions
-  // so we just return child if it exists
   if (!vm) {
-    if (childVal && typeof childVal !== 'function') {
+    // in a Vue.extend merge, both should be functions
+    if (!childVal) {
+      return parentVal
+    }
+    if (typeof childVal !== 'function') {
       _.warn(
         'The "data" option should be a function ' +
         'that returns a per-instance value in component ' +
         'definitions.'
       )
-      return
+      return parentVal
     }
-    return childVal || parentVal
-  }
-  var instanceData = typeof childVal === 'function'
-    ? childVal.call(vm)
-    : childVal
-  var defaultData = typeof parentVal === 'function'
-    ? parentVal.call(vm)
-    : undefined
-  if (instanceData) {
-    // mix default data into instance data
-    for (var key in defaultData) {
-      if (!instanceData.hasOwnProperty(key)) {
-        instanceData.$add(key, defaultData[key])
-      }
+    if (!parentVal) {
+      return childVal
+    }
+    // when parentVal & childVal are both present,
+    // we need to return a function that returns the
+    // merged result of both functions... no need to
+    // check if parentVal is a function here because
+    // it has to be a function to pass previous merges.
+    return function mergedDataFn () {
+      return mergeData(
+        childVal.call(this),
+        parentVal.call(this)
+      )
     }
-    return instanceData
   } else {
-    return defaultData
+    // instance merge, return raw object
+    var instanceData = typeof childVal === 'function'
+      ? childVal.call(vm)
+      : childVal
+    var defaultData = typeof parentVal === 'function'
+      ? parentVal.call(vm)
+      : undefined
+    if (instanceData) {
+      return mergeData(instanceData, defaultData)
+    } else {
+      return defaultData
+    }
   }
 }
 

+ 22 - 4
test/unit/specs/util/merge-option_spec.js

@@ -151,12 +151,30 @@ describe('Util - Option merging', function () {
     expect(res.data).toBeUndefined()
   })
 
-  it('class data/el merge', function () {
+  it('class el merge', function () {
     function fn1 () {}
     function fn2 () {}
-    var res = merge({data:fn1, el:fn1}, {data:fn2})
-    expect(res.data).toBe(fn2)
-    expect(res.el).toBe(fn1)
+    var res = merge({el:fn1}, {el:fn2})
+    expect(res.el).toBe(fn2)
+  })
+
+  it('class data merge', function () {
+    function fn1 () {
+      return { a: 1, c: 4 }
+    }
+    function fn2 () {
+      return { a: 2, b: 3 }
+    }
+    // both present
+    var res = merge({data:fn1}, {data:fn2}).data()
+    expect(res.a).toBe(2)
+    expect(res.b).toBe(3)
+    expect(res.c).toBe(4)
+    // only parent
+    res = merge({data:fn1}, {}).data()
+    expect(res.a).toBe(1)
+    expect(res.b).toBeUndefined()
+    expect(res.c).toBe(4)
   })
 
   it('instanace el merge', function () {