簡體   English   中英

數據綁定的秘訣是什么?

[英]What's the secret to data-binding?

對於大多數JS框架和庫,它們帶來的價值通常以新結構的形式出現,如如何構建應用程序(Backbone,React),有效增強語言功能的新想法(Angular),或者僅僅是他們提供的方法已經過測試,快速且非常方便(jQuery)。

通常,他們提供的想法和方法都是JavaScript的簡單明了的用法,但是背后有一個非常聰明的團隊,他們找到有趣的方式來做事情,您可以仔細考慮並就膽量的工作方式做出可靠的猜測。

但是,我一直無法考慮通過雙向綁定JS模型來查看組件的能力。 使此功能起作用的這個功能的核心秘訣是什么? 從用戶輸入更改內部變量很簡單,但是相反呢? 您如何才能“知道” JS變量已更改以便立即更新顯示? 當然不能進行輪詢,那又如何呢?

每當您的JS塊運行該角度觸發時,當該塊完成執行時,它將運行摘要循環。 基本上,這會檢查所有可能更改的值,並且需要更新視圖。

如果angular沒有觸發代碼,那么它將不會知道可能有所更改,因此您的綁定可能會不同步。 例如,如果您運行類似的內容

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

Angular不會知道myValue更改,並且它實際上不會更新視圖。 這就是為什么Angular擁有自己的服務來做所有事情的原因。 例如$timeout$http

如果您有一些Angular不知道的回調函數,則可以通過調用$scope.$apply()手動告訴它檢查更改$scope.$apply()

有幾種方法可以做到這一點。 Object.observe很棒,但是缺乏良好的支持。 您也可以輪詢值,並保留對象的第二個副本進行比較。 您還可以編寫自己的顯式set / get方法來更新模型,就像骨干網一樣。

我經常使用的一種整潔方法是使用getters / 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

我可以說說Backbone是如何完成的,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的帶注釋的源來獲取實際的事件調度實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM