翻譯:Knockout 快速上手 - 5: 你需要知道的頂級特性 續


Utilities

Knockout 提供了許多可以你開發中使用的工具,你可以在 ko.utils 命名空間中找到它們,我最喜歡的工具如下所示:

  • extend: 這個方法將兩個對象合並在一起,調用這個方法之后,會將第二個對象的所有屬性,方法合並到第一個對象上。
  • unwrapObservable: 這個方法獲取一個屬性作為參數,然后返回它的值。比如 Knockout 的 Observable 屬性,或者一個簡單的屬性。這個函數在你希望在運行時獲取對象的實際值得時候很有用。
  • 所有的數組工具:Knockout 提供了許多對於數據操作的工具,允許你過濾,映射,或者刪除其中的項目。我經常在項目開始的時候,將這些方法附加到ko.observableArray.fn 上。

下面的代碼演示了使用方法。

// extend usage
var a = { val: 1 },
b = { val: 2 };

ko.utils.extend(a, b);
console.log(a.val); // console: 2

// unwrapObservable usage
var c = ko.observable(99), d = 98;
console.log(ko.utils.unwrapObservable(c)); // console: 99
console.log(ko.utils.unwrapObservable(d)); // console: 98

// array "map" utility function usage
var arr = [100, 101];
var mapped = ko.utils.arrayMap(arr, function (item) {
    return item + 50;
})

console.log(arr); // console: [ 150, 151 ]

Data-bind statements

我們一直關注 Knockout 的腳本庫,實際上,Knockout 被設計為可以簡單地將 JavaScript 對象綁定到 HTML 中。API 使用與 HTML5 兼容的 data-bind 語法。在我們前面的示例中,你可以看到可以簡單地將 HTML 元素的屬性綁定到 ViewModel 的屬性上。data-bind 語法允許使用逗號分隔的綁定定義,下面的示例演示了使用方式。

<span data-bind="text: myText"></span>
<div data-bind="visible: isVisible, with: someProp"></div>
<input data-bind="value: someVal,
    css: {
        'error': !someVal.isValid(),
        'success': someVal.isValid()
    }"/>

Applying bindings

applyBindings 是 Knockout 一切工作啟動的起點。大多數的示例都演示了將一個 ViewModel 作為參數的使用方式。但是你可以通過第二個參數來指定一個 DOM 對象,Knockout 將只會綁定到這個 DOM 節點及其子節點上。

多數的應用只有一個 ViewModel ,在調用 applyBinding 的時候,也僅僅傳遞一個 ViewModel 參數。但是,我創建過許多復雜的應用程序,在一個頁面中使用了多個 ViewModel 對象,使用多個 ViewModel 的分別處理提示,設置,還有當前用戶的信息等等。在這些情況下,通過限制 Knockout 綁定的節點數量,可以獲取性能的優勢。如果你僅僅需要更新頁面的部分內容,就不要通過 Knockout 綁定到整個頁面上。

Binding handlers

我曾經提到過 Knockout 提供了許多的擴展點。有一些比 Knockout 的 Binding handler 更方便。雖然通過 data-bind 語法實現了 binding handler 。Knockout 還允許我們自定義綁定的處理器,所以,我們可以實現,或者重寫,我們自定義的功能。

在 MVVM 風格的開發中, 我們會有兩種類型的綁定:單向和雙向綁定。單向的綁定是簡單的信息讀取,將 ViewModel 中的數據讀取出來綁定到 DOM 中。你可以想像出雙向的數據綁定就是在單向的基礎之上,將 DOM 對象的更新返回到 ViewModel 的屬性上。Knockout 允許我們創建所有類型的綁定,下面的代碼演示了基本處理器使用。

ko.bindingHandlers['myHandler'] = {
    init: function (element, valueAccessor, allBindingsAccessor,  viewModel, bindingContext) {
    },

    update: function (element, valueAccessor, allBindingsAccessor,    viewModel, bindingContext) {

    }
};

如你所見,我們提供了兩個鈎子來實現我們的邏輯。Init 和 update 函數。這些函數的參數如下所示:

  • element: 定義 data-bind 的元素
  • valueAccessor:返回 ViewModel 綁定屬性值得函數。如果綁定到 Observable 屬性,那么回返回這個 Observalbe,在我們的處理邏輯中,需要將這個 Observable 進行 upwarp處理。
  • allBindingAccessor:類似於 valueAccessor ,但是它返回一個包含所有綁定和綁定值的對象。
  • viewModel:傳遞給 applyBindings 的視圖模型或者根對象
  • bindingContext:專用的一個特殊對象,包含表示當前綁定上下文環境的特定信息。綁定上下文中有一個 $data 屬性表示當前的綁定,這個屬性經常與 viewModel 是相同的。還有 $parent 屬性和 $parents 屬性,表示綁定元素的上級節點。通常在使用 with 的時候才會使用這些屬性。

你可以在想,這些東西看起來都差不多,我們應該在哪里實現我們的業務邏輯呢?init 函數僅僅在調用 applyBinding 的時候調用一次。Knockout 遍歷整個 DOM 樹,查找 data-bind 語法,處理它們,在每個需要的綁定上,調用 init 方法。然后,在調用 init 方法之后,立即調用 update 方法,以后,在綁定發生變化的時候會多次調用這個方法 ( 如果是 Subscribable )。

我的處理方式是在 init 中注冊我所有的事件處理器 ( change, blur, focus ) ,然后在 update 中處理 HTML。

下面的代碼演示了常見的單向綁定,這個例子與 visible 正好相反,我們可以使用 isHidden 而不是 isVisible。

// invisible -> the inverse of 'visible'
ko.bindingHandlers['invisible'] = {
    update: function (element, valueAccessor) {
        var newValueAccessor = function () {
            // just return the opposite of the visible flag!
            return !ko.utils.unwrapObservable(valueAccessor());
        };

        return ko.bindingHandlers.visible.update(element,        newValueAccessor);

    }
};

下面的代碼演示了雙向的綁定,這個例子演示對一個數字的驗證,從元素中獲取數據傳遞到 ViewModel,在 ViewModel 發生變化的時候也可以傳遞到 DOM。

// simple number parsing
function parseNumber(strVal){
    return parseInt(strVal, 10);
}

// very basic two-way binding handler
ko.bindingHandlers['number'] = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        //handle the input changing
        ko.utils.registerEventHandler(element, "change", function () {
            var observable = valueAccessor();
            var number = parseNumber(element.value);
            if (number !== NaN) {
                observable(element.value);
            }
        });
    },

    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var number = parseNumber(value);
        if (number !== NaN) {
            element.setAttribute("value", number);
        }
    }
};

Summary

你可以看到 Knockout 是一個非常成熟的腳本庫,在這一節我們學到下面的內容:

  • Knockout 的核心對象和使用方式
  • Knockout 的實用工具
  • 如何創建和管理多個的 ViewModel
  • 定制綁定處理器

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM