Evan You 12 лет назад
Родитель
Сommit
2059be5a63
5 измененных файлов с 72 добавлено и 13 удалено
  1. 15 8
      src/compiler.js
  2. 14 5
      src/directives/index.js
  3. 9 0
      src/utils.js
  4. 26 0
      test/unit/specs/api.js
  5. 8 0
      test/unit/specs/utils.js

+ 15 - 8
src/compiler.js

@@ -94,10 +94,8 @@ function Compiler (vm, options) {
     // copy paramAttributes
     if (options.paramAttributes) {
         options.paramAttributes.forEach(function (attr) {
-            var val = el.getAttribute(attr)
-            vm[attr] = (isNaN(val) || val === null)
-                ? val
-                : Number(val)
+            var val = compiler.eval(el.getAttribute(attr))
+            vm[attr] = utils.checkNumber(val)
         })
     }
 
@@ -123,7 +121,9 @@ function Compiler (vm, options) {
     compiler.compile(el, true)
 
     // bind deferred directives (child components)
-    compiler.deferred.forEach(compiler.bindDirective, compiler)
+    compiler.deferred.forEach(function (dir) {
+        compiler.bindDirective(dir)
+    })
 
     // extract dependencies for computed properties
     compiler.parseDeps()
@@ -413,6 +413,7 @@ CompilerProto.compileNode = function (node) {
 
     var prefix = config.prefix + '-',
         attrs = slice.call(node.attributes),
+        params = this.options.paramAttributes,
         i = attrs.length, j, attr, isDirective, exps, exp, directive, dirname
 
     while (i--) {
@@ -438,7 +439,13 @@ CompilerProto.compileNode = function (node) {
             exp = TextParser.parseAttr(attr.value)
             if (exp) {
                 directive = Directive.parse('attr', attr.name + ':' + exp, this, node)
-                this.bindDirective(directive)
+                if (params && params.indexOf(attr.name) > -1) {
+                    // a param attribute... we should use the parent binding
+                    // to avoid circular updates like size={{size}}
+                    this.bindDirective(directive, this.parent)
+                } else {
+                    this.bindDirective(directive)
+                }
             }
         }
 
@@ -496,7 +503,7 @@ CompilerProto.compileTextNode = function (node) {
 /**
  *  Add a directive instance to the correct binding & viewmodel
  */
-CompilerProto.bindDirective = function (directive) {
+CompilerProto.bindDirective = function (directive, bindingOwner) {
 
     if (!directive) return
 
@@ -512,7 +519,7 @@ CompilerProto.bindDirective = function (directive) {
 
     // otherwise, we got more work to do...
     var binding,
-        compiler = this,
+        compiler = bindingOwner || this,
         key      = directive.key
 
     if (directive.isExp) {

+ 14 - 5
src/directives/index.js

@@ -14,11 +14,20 @@ module.exports = {
     partial   : require('./partial'),
     view      : require('./view'),
 
-    attr: function (value) {
-        if (value || value === 0) {
-            this.el.setAttribute(this.arg, value)
-        } else {
-            this.el.removeAttribute(this.arg)
+    attr: {
+        bind: function () {
+            var params = this.vm.$options.paramAttributes
+            this.isParam = params && params.indexOf(this.arg) > -1
+        },
+        update: function (value) {
+            if (value || value === 0) {
+                this.el.setAttribute(this.arg, value)
+            } else {
+                this.el.removeAttribute(this.arg)
+            }
+            if (this.isParam) {
+                this.vm[this.arg] = utils.checkNumber(value)
+            }
         }
     },
 

+ 9 - 0
src/utils.js

@@ -116,6 +116,15 @@ var utils = module.exports = {
                 : value
     },
 
+    /**
+     *  When setting value on the VM, parse possible numbers
+     */
+    checkNumber: function (value) {
+        return (isNaN(value) || value === null || typeof value === 'boolean')
+            ? value
+            : Number(value)
+    },
+
     /**
      *  simple extend
      */

+ 26 - 0
test/unit/specs/api.js

@@ -632,6 +632,32 @@ describe('API', function () {
                     assert.strictEqual(v.$data.c, null)
                 })
 
+                it('should be able in bind data from parents', function (done) {
+                    var v = new Vue({
+                        template: '<div v-component="test" v-ref="child"></div>',
+                        data: {
+                            size: 123
+                        },
+                        components: {
+                            test: {
+                                paramAttributes: ['size'],
+                                template: '<div class="child" size="{{size}}"></div>'
+                            }
+                        }
+                    })
+                    var childAttr = v.$el.querySelector('.child').getAttribute('size')
+                    assert.strictEqual(childAttr, '123')
+
+                    v.size = 234
+
+                    nextTick(function () {
+                        var childAttr = v.$el.querySelector('.child').getAttribute('size')
+                        assert.strictEqual(childAttr, '234')
+                        assert.strictEqual(v.$.child.size, 234)
+                        done()
+                    })
+                })
+
             })
 
             describe('parent', function () {

+ 8 - 0
test/unit/specs/utils.js

@@ -379,4 +379,12 @@ describe('Utils', function () {
 
     })
 
+    describe('checkNumber', function () {
+        // TODO
+    })
+
+    describe('objectToArray', function () {
+        // TODO
+    })
+
 })