数据绑定的秘诀是什么?

时间:2015-07-15 19:09:02

标签: javascript angularjs data-binding bind

对于大多数JS框架和库,它们带来的价值通常是关于如何构建应用程序(Backbone,React)的新结构,或者有效地启动语言的新想法(Angular),或者只是他们提供的方法经过了充分的测试,快速且非常方便(jQuery)。

通常他们提供的想法和方法都非常直接地使用JavaScript,但是有一个非常聪明的团队,它可以找到有趣的方法来做你能想到的事情,并对胆量如何运作有一个可靠的猜测。

但是,我一直无法通过双向绑定JS模型来查看组件的能力。这项功能的核心是什么秘诀使这项工作?从用户输入更改内部变量很简单,但反过来呢?当JS变量何时发生变化以便立即更新显示时,您将如何“知道”?当然它不能轮询,那么呢?

3 个答案:

答案 0 :(得分:2)

每当你的JS块运行该角度触发时,它将在块完成执行时运行摘要循环。这基本上会检查可能已更改的所有值,并且需要更新视图。

如果角度没有触发代码,那么它就不会知道某些内容可能会发生变化,因此您的绑定可能会失去同步。例如,如果你运行这样的东西

setTimeout(function() {$scope.myValue = '123'});

Angular不知道myValue发生了变化,实际上它不会更新视图。这就是为什么Angular拥有自己的服务来做所有事情的原因。例如$timeout$http

如果您有一些Angular不知道的回调函数,您可以通过调用$scope.$apply()

手动告诉它检查更改

答案 1 :(得分:1)

有几种方法可以做到这一点。 Object.observe很棒,但缺乏良好的支持。您也可以轮询值,保留对象的第二个副本以进行比较。您也可以编写自己的显式set / get方法来更新模型,如骨干。

我经常使用的一个简洁方法是使用getter / setter来保持模型与dom同步:

//a demo "model" of data:
model = {
    name: "Fred"
};

function change(k,v){alert([k,v]);} // a stand-in change monitor for demo

// iterate model and replace values with getter/setter combos: 
Object.keys(model).forEach(function(key) {
    var val = model[key];
    delete model[key];
    Object.defineProperty(model, key, {
        get: function() {
            return val;
        },
        set: function(v) {
            val = v;
            change(key, val);
        } //call change upon setting
    });
    change(key, val); //update view "onload"
}); // alerts "Fred";

//update model (fires change() with "name" and "sally" arguments:
model.name="sally"; // alerts  "sally";

更改功能非常简单,对于您的情况应该只找到绑定到键的元素。 这里的优点是你不需要特殊的自定义CRUD方法,你可以像1999年那样通过赋值来修改对象属性。它也没有轮询,并且一直正常工作到IE9和任何其他ES5环境。这是在没有自定义方法的情况下绑定JS> DOM(afaik)的最简单方法。

它确实有一些限制:嵌套对象很难获得/设置,你不能一次完成整个对象,你只能观察"原语。数组也是一个问题:你无法用getter / setter替换expando属性而没有副作用。但是,在相对平坦的JSON安全数据集合中,get / set是一个魅力,不需要复杂的库来实现。

使用此方法结帐完整示例:http://pagedemos.com/xg3szbguqnwu/4

答案 2 :(得分:0)

我可以谈谈它在Backbone中的表现,后者对数据绑定的看法相对较低。

它是1.控制属性设置器方法的库的组合2.当属性改变时(例如通过调度事件)调用回调函数以便更新UI。

基本伪代码是这样的:

class Model:

  method set(name, value):
    if value != this.attributes[name]
      this.triggerEvent('change', name, value)
      this.attributes[name] = value

m = new Model()
someInputWidget.onEvent('userChangedInput', function(value) {
  m.set(someInputWidget.name, value)
})
m.onEvent('change', function(name, value) {
  getInputWidgetByName(name).setValue(value)
})

Backbone没有对UI进行任何数据绑定,但您可以参考Backbone的annotated source来实现事件调度实现。