文章出處

Knockout observables提供了支持讀取/寫入值并在值改變時通知訂閱者所需的基本功能。 但在某些情況下,您可能希望向可觀察者添加其他功能。 這可能包括通過在可觀察者前面放置一個可寫的計算可觀察符來向可觀察或截取寫入添加額外的屬性。 敲除擴展器提供了一種簡單和靈活的方式來對可觀察者進行這種類型的擴充。

如何創建擴展器

創建擴展器涉及向ko.extenders對象添加一個函數。 函數接受observable本身作為第一個參數和第二個參數中的任何選項。 然后它可以返回observable或返回一些新的像一個計算的observable,它以某種方式使用原來的observable。

這個簡單的logChange擴展器訂閱了observable,并使用控制臺寫入任何更改以及可配置的消息。

ko.extenders.logChange = function(target, option) {
    target.subscribe(function(newValue) {
       console.log(option + ": " + newValue);
    });
    return target;
};

您將通過調用observable的extend函數并傳遞包含日志Change屬性的對象來使用此擴展器。

this.firstName = ko.observable("Bob").extend({logChange: "first name"});

如果firstName observable值更改為Ted,那么控制臺將顯示名字:Ted。

示例1:強制輸入為數字

此示例創建一個擴展器,該擴展器強制對可觀察對象的寫入被四舍五入到可配置的精度級別。 在這種情況下,擴展器將返回一個新的可寫的計算可觀察,它將位于真正的可觀察的攔截寫入之前。

(round to whole number)

(round to two decimals)

UI源碼:

<p><input data-bind="value: myNumberOne" /> (round to whole number)</p>
<p><input data-bind="value: myNumberTwo" /> (round to two decimals)</p>

視圖模型源碼:

ko.extenders.numeric = function(target, precision) {
    //create a writable computed observable to intercept writes to our observable
    var result = ko.pureComputed({
        read: target,  //always return the original observables value
        write: function(newValue) {
            var current = target(),
                roundingMultiplier = Math.pow(10, precision),
                newValueAsNum = isNaN(newValue) ? 0 : +newValue,
                valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
 
            //only write if it changed
            if (valueToWrite !== current) {
                target(valueToWrite);
            } else {
                //if the rounded value is the same, but a different value was written, force a notification for the current field
                if (newValue !== current) {
                    target.notifySubscribers(valueToWrite);
                }
            }
        }
    }).extend({ notify: 'always' });
 
    //initialize with current value to make sure it is rounded appropriately
    result(target());
 
    //return the new computed observable
    return result;
};
 
function AppViewModel(one, two) {
    this.myNumberOne = ko.observable(one).extend({ numeric: 0 });
    this.myNumberTwo = ko.observable(two).extend({ numeric: 2 });
}
 
ko.applyBindings(new AppViewModel(221.2234, 123.4525));

注意,為了自動從UI中刪除被拒絕的值,有必要在計算的observable上使用.extend({notify:'always'})。 沒有這個,用戶可能輸入一個無效的newValue,當四舍五入得到一個不變的valueToWrite。 然后,由于模型值不會改變,因此在UI中沒有更新文本框的通知。 使用{notify:'always'}會導致文本框刷新(刪除被拒絕的值),即使計算的屬性沒有更改值。

示例2:向可觀察者添加驗證

此示例創建一個擴展器,允許將observable標記為必需。 這個擴展器不是返回一個新的對象,而是簡單地向現有的observable添加額外的子可觀察量。 因為observables是函數,它們實際上可以有自己的屬性。 但是,當視圖模型轉換為JSON時,子可觀察項將被刪除,我們將只剩下我們的實際observable的值。 這是一個很好的方法來添加只與UI相關的附加功能,而不需要發送回服務器。

UI源碼:

<p data-bind="css: { error: firstName.hasError }">
    <input data-bind='value: firstName, valueUpdate: "afterkeydown"' />
    <span data-bind='visible: firstName.hasError, text: firstName.validationMessage'> </span>
</p>
<p data-bind="css: { error: lastName.hasError }">
    <input data-bind='value: lastName, valueUpdate: "afterkeydown"' />
    <span data-bind='visible: lastName.hasError, text: lastName.validationMessage'> </span>
</p>

視圖模型暈嗎:

ko.extenders.required = function(target, overrideMessage) {
    //add some sub-observables to our observable
    target.hasError = ko.observable();
    target.validationMessage = ko.observable();
 
    //define a function to do validation
    function validate(newValue) {
       target.hasError(newValue ? false : true);
       target.validationMessage(newValue ? "" : overrideMessage || "This field is required");
    }
 
    //initial validation
    validate(target());
 
    //validate whenever the value changes
    target.subscribe(validate);
 
    //return the original observable
    return target;
};
 
function AppViewModel(first, last) {
    this.firstName = ko.observable(first).extend({ required: "Please enter a first name" });
    this.lastName = ko.observable(last).extend({ required: "" });
}
 
ko.applyBindings(new AppViewModel("Bob","Smith"));

應用多個擴展程序

多個擴展器可以在對可觀察者的.extended方法的單個調用中應用。

this.firstName = ko.observable(first).extend({ required: "Please enter a first name", logChange: "first name" });

在這種情況下,required和logChange擴展器都會對我們的observable執行。


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()