2. 数据绑定
2.1 数据绑定的原理
数据绑定是一种很便捷的特性,一些RIA框架带有双向绑定功能,比如Flex和Silverlight,当某个数据发生变更时,所绑定的界面元素也发生变更,当界面元素的值发生变化时,数据也跟着变化,这种功能在处理表单数据的填充和收集时,是非常有用的。
在HTML中,原生是没有这样的功能的,但有些框架做到了,它们是怎么做到的呢?我们来做个简单的试试,顺便探讨一下其中原理。
先看数据到界面上的的绑定,比如:
1 2 3 4 |
<input vm-value="name"/> var person = { name: "Tom" }; |
如果我们给name重新赋值,person.name = “Jerry”,怎么才能让界面得到变更?
从直觉来说,我们需要在name发生改变的时候,触发一个事件,或者调用某个指定的方法,然后才好着手做后面的事情,比如:
1 2 3 4 5 6 7 |
var person = { name: "Tom", setName: function(newName) { this.name = newName; //do something } }; |
这样我们可以在setName里面去给input赋值。推而广之,为了使得实体包含的多个属性都可以运作,可以这么做:
1 2 3 4 5 6 7 8 |
var person = { name: "Tom", gender: 5 set: function(key, value) { this[key] = value; //do something } }; |
或者合并两个方法,只判断是否传了参数:
1 2 3 4 5 6 7 8 |
Person.prototype.name = function(value) { if (arguments.length == 0) { return this._name; } else { this._name = value; } } |
这种情况下,赋值的时候就是person.name(“Tom”),取值的时候就是var name = person.name()了。
有一些框架是通过这种方式来变通实现数据绑定的,对数据的写入只能通过方法调用。但这种方式很不直接,我们来想点别的办法。
在C#等一些语言里,有一种东西叫做存取器,比如说:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Person { private string name; public string Name { get { return name; } set { name = value; } } } |
用的时候,person.Name = “Jerry”,就会调用到set里,相当于是个方法。
这一点非常好,很符合我们的需要,那JavaScript里面有没有类似存取器的特性呢?老早以前是没有的,但现在有了,那就是Object.defineProperty,它的第三个参数就是可选的存取函数。比如说:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var person = {}; // Add an accessor property to the object. Object.defineProperty(person, "name", { set: function (value) { this._name = value; //do something }, 有用的。
在HTML中,原生是没有这样的功能的,但有些框架做到了,它们是怎么做到的呢?我们来做个简单的试试,顺便探讨一下其中原理。 先看数据到界面上的的绑定,比如:
如果我们给name重新赋值,person.name = “Jerry”,怎么才能让界面得到变更? 从直觉来说,我们需要在name发生改变的时候,触发一个事件,或者调用某个指定的方法,然后才好着手做后面的事情,比如:
这样我们可以在setName里面去给input赋值。推而广之,为了使得实体包含的多个属性都可以运作,可以这么做:
或者合并两个方法,只判断是否传了参数:
这种情况下,赋值的时候就是person.name(“Tom”),取值的时候就是var name = person.name()了。 有一些框架是通过这种方式来变通实现数据绑定的,对数据的写入只能通过方法调用。但这种方式很不直接,我们来想点别的办法。 在C#等一些语言里,有一种东西叫做存取器,比如说:
用的时候,person.Name = “Jerry”,就会调用到set里,相当于是个方法。 这一点非常好,很符合我们的需要,那JavaScript里面有没有类似存取器的特性呢?老早以前是没有的,但现在有了,那就是Object.defineProperty,它的第三个参数就是可选的存取函数。比如说:
|