Просмотр исходного кода

prop watchers should be triggered on reference change only (fix #1683)

Evan You 10 лет назад
Родитель
Сommit
8def6c7400

+ 5 - 1
src/directives/internal/prop.js

@@ -31,7 +31,9 @@ module.exports = {
         filters: prop.filters,
         // important: props need to be observed on the
         // v-for scope if present
-        scope: this._scope
+        scope: this._scope,
+        // only fire callback when reference has changed
+        refOnly: true
       }
     )
 
@@ -49,6 +51,8 @@ module.exports = {
           childKey,
           function (val) {
             parentWatcher.set(val)
+          }, {
+            refOnly: true
           }
         )
       })

+ 9 - 7
src/observer/index.js

@@ -179,13 +179,15 @@ function defineReactive (obj, key, val) {
     get: function metaGetter () {
       if (Dep.target) {
         dep.depend()
-        if (childOb) {
-          childOb.dep.depend()
-        }
-        if (_.isArray(val)) {
-          for (var e, i = 0, l = val.length; i < l; i++) {
-            e = val[i]
-            e && e.__ob__ && e.__ob__.dep.depend()
+        if (!Dep.refOnly) {
+          if (childOb) {
+            childOb.dep.depend()
+          }
+          if (_.isArray(val)) {
+            for (var e, i = 0, l = val.length; i < l; i++) {
+              e = val[i]
+              e && e.__ob__ && e.__ob__.dep.depend()
+            }
           }
         }
       }

+ 3 - 0
src/watcher.js

@@ -20,6 +20,7 @@ var uid = 0
  *                 - {Boolean} user
  *                 - {Boolean} sync
  *                 - {Boolean} lazy
+ *                 - {Boolean} refOnly
  *                 - {Function} [preProcess]
  *                 - {Function} [postProcess]
  * @constructor
@@ -179,6 +180,7 @@ Watcher.prototype.set = function (value) {
 
 Watcher.prototype.beforeGet = function () {
   Dep.target = this
+  Dep.refOnly = !!this.refOnly
   this.newDeps = Object.create(null)
 }
 
@@ -188,6 +190,7 @@ Watcher.prototype.beforeGet = function () {
 
 Watcher.prototype.afterGet = function () {
   Dep.target = null
+  Dep.refOnly = false
   var ids = Object.keys(this.deps)
   var i = ids.length
   while (i--) {

+ 24 - 0
test/unit/specs/directives/internal/prop_spec.js

@@ -550,5 +550,29 @@ if (_.inBrowser) {
       })
       expect(_.warn).not.toHaveBeenCalled()
     })
+
+    // #1683
+    it('should only trigger sync on reference change', function (done) {
+      var vm = new Vue({
+        el: el,
+        data: {
+          items: [1, 2]
+        },
+        template: '<comp :items.sync="items"></comp>',
+        components: {
+          comp: {
+            props: ['items']
+          }
+        }
+      })
+      var child = vm.$children[0]
+      child.items.push(3) // this should not trigger parent to sync it down
+      var newArray = child.items = [4]
+      _.nextTick(function () {
+        expect(child.items).toBe(newArray)
+        expect(vm.items).toBe(newArray)
+        done()
+      })
+    })
   })
 }