瀏覽代碼

v-bind should be in deep mode when used on objects for class, style and attributes

Evan You 10 年之前
父節點
當前提交
1e575a75e2
共有 4 個文件被更改,包括 46 次插入11 次删除
  1. 2 0
      src/directives/internal/class.js
  2. 4 0
      src/directives/public/bind.js
  3. 10 11
      src/watcher.js
  4. 30 0
      test/unit/specs/misc_spec.js

+ 2 - 0
src/directives/internal/class.js

@@ -4,6 +4,8 @@ var removeClass = _.removeClass
 
 module.exports = {
 
+  deep: true,
+
   update: function (value) {
     if (value && typeof value === 'string') {
       this.handleObject(stringToObject(value))

+ 4 - 0
src/directives/public/bind.js

@@ -30,6 +30,10 @@ module.exports = {
   bind: function () {
     var attr = this.arg
     var tag = this.el.tagName
+    // should be deep watch on object mode
+    if (!attr) {
+      this.deep = true
+    }
     // handle interpolation bindings
     if (this.descriptor.interp) {
       // only allow binding on native attributes

+ 10 - 11
src/watcher.js

@@ -325,19 +325,18 @@ Watcher.prototype.teardown = function () {
  * getters, so that every nested property inside the object
  * is collected as a "deep" dependency.
  *
- * @param {Object} obj
+ * @param {*} val
  */
 
-function traverse (obj) {
-  var key, val, i
-  for (key in obj) {
-    val = obj[key]
-    if (_.isArray(val)) {
-      i = val.length
-      while (i--) traverse(val[i])
-    } else if (_.isObject(val)) {
-      traverse(val)
-    }
+function traverse (val) {
+  var i, keys
+  if (_.isArray(val)) {
+    i = val.length
+    while (i--) traverse(val[i])
+  } else if (_.isObject(val)) {
+    keys = Object.keys(val)
+    i = keys.length
+    while (i--) traverse(val[keys[i]])
   }
 }
 

+ 30 - 0
test/unit/specs/misc_spec.js

@@ -313,4 +313,34 @@ describe('Misc', function () {
       }
     })
   })
+
+  it('deep watch for class, style and bind', function (done) {
+    var el = document.createElement('div')
+    var vm = new Vue({
+      el: el,
+      template: '<div :class="classes" :style="styles" v-bind="attrs"></div>',
+      data: {
+        classes: { a: true, b: false },
+        styles: { color: 'red', fontSize: '14px' },
+        attrs: { a: 1, b: 2 }
+      }
+    })
+    var div = el.firstChild
+    expect(div.className).toBe('a')
+    expect(div.style.color).toBe('red')
+    expect(div.style.fontSize).toBe('14px')
+    expect(div.getAttribute('a')).toBe('1')
+    expect(div.getAttribute('b')).toBe('2')
+    vm.classes.b = true
+    vm.styles.color = 'green'
+    vm.attrs.a = 3
+    Vue.nextTick(function () {
+      expect(div.className).toBe('a b')
+      expect(div.style.color).toBe('green')
+      expect(div.style.fontSize).toBe('14px')
+      expect(div.getAttribute('a')).toBe('3')
+      expect(div.getAttribute('b')).toBe('2')
+      done()
+    })
+  })
 })