kendo-ui的MVVM模式


摘要:

  MVVM(Model View ViewModel)是一種幫助開發者將數據從模型分離的設計模式。MVVM的ViewModel負責將數據對象從模型中分離出來,通過這種方式數據就很容易控制數據如何顯示在視圖上。

創建View-Model對象:

  首先我們需要創建一個View-Model對象,他是控制你的數據顯示在視圖上。

創建對象

var viewModel = kendo.observable({
    name: "John Doe",
    displayGreeting: function() {
        var name = this.get("name");
        alert("Hello, " + name + "!!!");
    }
});

創建視圖

<div id="view">
    <input data-bind="value: name" />
    <button data-bind="click: displayGreeting">Display Greeting</button>
</div>

 

然后將對象綁定到視圖上

kendo.bind($("#view"), viewModel);

如何工作呢?

  input元素的value值是通過data-bind屬性綁定到viewModel的name字段,這個綁定是雙向的,當改變viewModel的name字段值,視圖上input的value值也會被改變。當改變視圖上input元素的value值,viewModel的name字段也會被改變。

綁定:

  ​元素通過data-bind屬性綁定到viewModel,當你想通過一個對象綁定到視圖上,你可以像下面這樣定義視圖模型

<div data-bind="text: person.name">
</div>
<script>
var viewModel = kendo.observable({
    person: {
        name: "John Doe"
    }
});
kendo.bind($("div"), viewModel);
</script>

 

data-bind還支持的屬性有source, html, attr, visible, enabled等,支持多個屬性,以逗號分隔。

注意:

  綁定不是javascript,像下面這樣的綁定就是不對的

<div data-bind="text: person.name.toLowerCase()"></div>

 

ObservableObject:

  kendo.data.ObservableObject是MVVM模式中非常重要的一部分,它支持跟蹤變化和通知用戶發生變化,所有的視圖模型對象都繼承它。

創建ObservableObject

var viewModel1 = new kendo.data.ObservableObject( {
  field1: "value1",
  field2: "value2"
});
 
var viewModel2 = kendo.observable( {
  field1: "value1",
  field2: "value2"
});

 

上面兩種方式都可以創建ObservableObject

注意:視圖模型必須在定義ObservableObject之后使用,否則無效。

設置與獲取屬性值:

   我們可以通過viewModel對象來獲取屬性值,如下:

var viewModel = kendo.observable({
    name: "John Doe"
});
 
viewModel.set("name", "Jane Doe"); //set the "name" field to "Jane Doe"
 
var name = viewModel.get("name");
alert(name); // shows "Jane Doe"

 

關鍵字this:

  我們可以通過this來獲取視圖模型的其他屬性值,如下:

<span data-bind="text: fullName"></span>
<script>
var viewModel = kendo.observable({
    firstName: "John",
    lastName: "Doe",
    fullName: function() {
        return this.get("firstName") + " " + this.get("lastName");
    }
});
 
kendo.bind($("span"), viewModel);
</script>

 

 

data-bind屬性:

attr:

  attr可以用來綁定DOM元素的屬性,例如:href、title等,對於多個屬性我們可以用對象來綁定,如下:

<img id="logo" data-bind="attr: { src: imageSource, alt: imageAlt }" />
<script>
var viewModel = kendo.observable({
    imageSource: "http://www.telerik.com/image/kendo-logo.png",
    imageAlt: "Kendo Logo"
});
 
kendo.bind($("#logo"), viewModel);
</script>

顯示到視圖上就會變成如下:

<img id="logo" src="http://www.telerik.com/image/kendo-logo.png" alt="Kendo Logo"" />

checked:

  checked屬性使用來選擇復選框或者單選框,屬性值為true或false,如下:

<input type="checkbox" data-bind="checked: isChecked" />
<script>
var viewModel = kendo.observable({
    isChecked: false
});
 
kendo.bind($("input"), viewModel);
</script>

對於多個復選框,根據value值來決定選中哪一個復選框,屬性值是一個數組,如下:

<input type="checkbox" value="Red"   data-bind="checked: colors" />
<input type="checkbox" value="Green" data-bind="checked: colors" />
<input type="checkbox" value="Blue"  data-bind="checked: colors" />
<script>
var viewModel = kendo.observable({
    colors: ["Red"]
});
 
kendo.bind($("input"), viewModel);
</script>

單選框,如下:

<input type="radio" value="Red"   name="color" data-bind="checked: selectedColor" />
<input type="radio" value="Green" name="color" data-bind="checked: selectedColor" />
<input type="radio" value="Blue"  name="color" data-bind="checked: selectedColor" />
<script>
var viewModel = kendo.observable({
    selectedColor: "Green"
});
 
kendo.bind($("input"), viewModel);
</script>

注意:單選框應該有相同的name值,checked只適合可以勾選的元素。

 click:

  click屬性將綁定一個方法到視圖模型上,當點擊這個DOM元素該方法將會被調用。

<div id="view">
<span data-bind="click: showDescription">Show description</span>
<span data-bind="visible: isDescriptionShown, text: description"></span>
 
<script>
var viewModel = kendo.observable({
    description: "Description",
    isDescriptionShown: false,
    showDescription: function(e) {
        // show the span by setting isDescriptionShown to true
        this.set("isDescriptionShown", true);
    }
});
 
kendo.bind($("#view"), viewModel);
</script>
 </div>

 

我們也可以通過events屬性來綁定click事件,如下:

<span data-bind="click: clickHandler"></span>
 
<span data-bind="events: { click: clickHandler }"></span>

阻止事件冒泡

  我們可以使用stopPropagation來阻止click事件冒泡,如下:

<span data-bind="click: click">Click</span>
<script>
var viewModel = kendo.observable({
    click: function(e) {
        e.stopPropagation();
    }
});
 
kendo.bind($("span"), viewModel);
</script>

阻止默認事件

  使用preventDefault方法來阻止瀏覽器默認行為。

<a href="http://example.com" data-bind="click: click">Click</span>
<script>
var viewModel = kendo.observable({
    click: function(e) {
        // stop the browser from navigating to http://example.com
        e.preventDefault();
    }
});
 
kendo.bind($("a"), viewModel);
</script>

 

custom:

   kendo MVVM提供自定義綁定屬性,這有利於我們自己做一些擴展。我們可以通過kendo.data.Binder來注冊一個屬性。

單項綁定

  這種自定義屬性當視圖模型的屬性值改變時,DOM元素將被更新,但是當DOM元素改變時並不會更新視圖模型屬性值。如下:

<script>
    kendo.data.binders.slide = kendo.data.Binder.extend({
        refresh: function() {
            var value = this.bindings["slide"].get();
 
            if (value) {
                $(this.element).slideDown();
            } else {
                $(this.element).slideUp();
            }
        }
    });
 
    var viewModel = kendo.observable({
        slideValue: true
    });
 
    kendo.bind(document.body, viewModel);
</script>
 
<div id="target" data-bind="slide: slideValue">
    One Big Orange Square.
</div>

 

雙向綁定

  這種自定義的屬性支持雙向綁定,即當DOM元素改變時會觸發視圖模型的改變,當視圖模型屬性值改變時會觸發DOM元素的改變。如下:

<script>
    kendo.data.binders.numericValue = kendo.data.Binder.extend({
        init: function(element, bindings, options) {
            //call the base constructor
            kendo.data.Binder.fn.init.call(this, element, bindings, options);
 
            var that = this;
            //listen for the change event of the element
            $(that.element).on("change", function() {
                that.change(); //call the change function
            });
        },
        refresh: function() {
            var that = this,
                value = that.bindings["numericValue"].get(); //get the value from the View-Model
 
            $(that.element).val(value); //update the HTML input element
        },
        change: function() {
            var value = this.element.value;
            //in this example the View-Model will be updated only if the value of the input is a number
            if (!isNaN(value)) {
                this.bindings["numericValue"].set(value); //update the View-Model
            }
        }
    });
 
    //View-Model source
    var viewModel = kendo.observable({
        number: 10
    });
 
    kendo.bind(document.body, viewModel);
</script>
 
<!-- View source -->
<input data-bind="numericValue: number" />
Input value: <span data-bind="text: number" />

 

組件綁定

  這種自定義屬性支持當視圖模型屬性值改變時會觸發組件的改變。如下:

//the following example demonstrates how to bind the max value of a NumericTextBox widget
kendo.data.binders.widget.max = kendo.data.Binder.extend({
    init: function(widget, bindings, options) {
        //call the base constructor
        kendo.data.Binder.fn.init.call(this, widget.element[0], bindings, options);
    },
    refresh: function() {
        var that = this,
        value = that.bindings["max"].get(); //get the value from the View-Model
        $(that.element).data("kendoNumericTextBox").max(value); //update the widget
    }
});
 
<!-- View source -->
<input data-role="numerictextbox" id="numeric" data-bind="value: value, max: max" />

 

自定義屬性的方法講解

init

    init​類似於構造函數,如果這個函數被重寫了,其基本構造函數首先被顯示調用。

refresh

    ​refresh負責更新DOM元素。當視圖模型的屬性值改變時,它會被執行。
change

    ​change負責更新視圖模型的屬性值。DOM元素發生變化時,它會被執行。

disabled:

  ​disabled是禁用DOM元素,屬性值為true或false。適合的DOM元素為:input、select、textarea。當DOM元素的disabled屬性值被設置為true時,則他的value值不能被改變。

<div id="view">
<input type="text" data-bind="value: name, disabled: isNameDisabled" />
<button data-bind="click: disableInput">Disable</button>
 
<script>
var viewModel = kendo.observable({
    isNameDisabled: false,
    name: "John Doe",
    disableInput: function() {
        this.set("isNameDisabled", true);
    }
});
 
kendo.bind($("#view"), viewModel);
</script>
 </div>

 

注意:0, null, undefined,"",''都會被當成false。

enable:

  與disabled相同,功能相反。

 events:

  events將視圖模型定義的方法綁定到DOM元素上,當對應事件在DOM元素發生時,該方法會被執行。如下:

<div id="view">
    <span data-bind="events: { mouseover: showDescription, mouseout: hideDescription }">Show description</span>
    <span data-bind="visible: isDescriptionShown, text: description"></span>
</div>
<script>
    var viewModel = kendo.observable({
        description: "Description",
        isDescriptionShown: false,
        showDescription: function(e) {
            // show the span by setting isDescriptionShown to true
            this.set("isDescriptionShown", true);
        },
        hideDescription: function(e) {
            // hide the span by setting isDescriptionShown to false
            this.set("isDescriptionShown", false);
        }
    });
 
    kendo.bind($("#view"), viewModel);
</script>

 

html:

  html是將視圖模型定義的值以html的形式插入到DOM元素內。如下:

<span data-bind="html: name"></span>
<script>
var viewModel = kendo.observable({
    name: "<strong>John Doe</strong>"
});
 
kendo.bind($("span"), viewModel);
</script>

結果為

<span><strong>John Doe</strong></span>

注意:並不是所有DOM元素都支持html屬性,比如table。他只適合內部沒有固定結構的html元素。

invisible:

   invisible控制DOM元素是否顯示。屬性值true或false,當設置為true時,DOM元素將被隱藏,對應css的display屬性將被設置為none。如下:

<div id="view">
    <div data-bind="invisible: isInvisible">some content
    </div>
    <button data-bind="click: show">Show</button>
</div>
<script>
var viewModel = kendo.observable({
    isInvisible: true,
    show: function() {
        this.set("isInvisible", false);
    }
});
 
kendo.bind($("#view"), viewModel);
</script>

初始div元素是隱藏的,因為isInvisible設置為true,當點擊按鈕時,isInvisible被設置為false,div元素顯示。

source:

  source用來渲染DOM元素的模板,模板是通過data-template屬性來指定,屬性值為模板的id,如果未指定則會根據元素的name值。如果視圖模型中的屬性值為數組時,會自動循環每一項並渲染模板到DOM元素內。

<ul data-template="ul-template" data-bind="source: products">
</ul>
<script id="ul-template" type="text/x-kendo-template">
    <li>
        id: <span data-bind="text: id"></span>
        name: <span data-bind="text: name"></span>
    </li>
</script>
<script>
var viewModel = kendo.observable({
    products: [
        { id: 1, name: "Coffee" },
        { id: 2, name: "Tea" },
        { id: 3, name: "Juice" }
    ]
});
 
kendo.bind($("ul"), viewModel);
</script>

結果為

<ul>
    <li>
        id: <span>1</span>
        name: <span>Coffee</span>
    </li>
    <li>
        id: <span>2</span>
        name: <span>Tea</span>
    </li>
    <li>
        id: <span>3</span>
        name: <span>Juice</span>
    </li>
</ul>

 

如果數組中不全是對象,則可以使用this代替當前屬性值,如下:

<ul data-template="ul-template" data-bind="source: products">
</ul>
<script id="ul-template" type="text/x-kendo-template">
    <li data-bind="text: this"></li>
</script>
<script>
var viewModel = kendo.observable({
    products: [ "Coffee", "Tea", "Juice" ]
});
 
kendo.bind($("ul"), viewModel);
</script>

 

結果為

<ul>
    <li>Coffee</li>
    <li>Tea</li>
    <li>Juice</li>
</ul>

給select元素設置source屬性:

<select data-text-field="name" data-value-field="id"
       data-bind="source: products"></select>
<script>
var viewModel = kendo.observable({
    products: [
        { id: 1, name: "Coffee" },
        { id: 2, name: "Tea" },
        { id: 3, name: "Juice" }
    ]
});
 
kendo.bind($("select"), viewModel);
</script>

 

顯示在視圖上為

<select>
    <option value="1">Coffee</option>
    <option value="2">Tea</option>
    <option value="3">Juice</option>
</select>

style:

  style屬性用來設置DOM元素的樣式,如下:

<span data-bind="style: {color: priceColor, fontWeight: priceFontWeight},
             text: price"></span>
 
<script>
var viewModel = kendo.observable({
    price: 42,
    priceColor: function() {
        var price = this.get("price");
 
        if (price <= 42) {
            return "#00ff00";
        } else {
            return "#ff0000";
        }
    },
    priceFontWeight: function() {
        var price = this.get("price");
 
        if (price <= 42) {
            return "bold";
        } else {
            return ""; //will reset the font weight to its default value
        }
    }
});
 
kendo.bind($("span"), viewModel);
</script>

 

結果為

<span style="color: #00ff00; font-weight: bold">42</span>

注意:對於這種font-weight, font-size, background-color應該使用駝峰格式。

text:

  ​text用來設置元素文本內容,如下:

<span data-bind="text: name"></span>
<script>
var viewModel = kendo.observable({
    name: "John Doe"
});

kendo.bind($("span"), viewModel);
</script>

 

結果為

<span>John Doe</span>

 

value:

  value屬性用來設置DOM元素的value值,所以他只適合帶有value屬性的DOM元素,比如inputtextarea和select。此屬性是雙向綁定的,即任何一方改變都會觸發另一方的改變。如下:

<div id="view">
    <input data-bind="value: inputValue" />
    <textarea data-bind="value: textareaValue"></textarea>
</div>
<script>
var viewModel = kendo.observable({
    inputValue: "Input value",
    textareaValue: "Textarea value"
});

kendo.bind($("#view"), viewModel);
</script>

 

注意:如果DOM元素改變並不是實時觸發視圖模型的屬性值改變,而是當DOM元素變換結束之后。

我們可以通過data-value-update屬性控制什么時候更新視圖模型,如下:

<div id="view">
    <input data-value-update="keyup" data-bind="value: inputValue" />
</div>
<script>
var viewModel = kendo.observable({
    inputValue: "InputValue"
});

kendo.bind($("#view"), viewModel);
</script>

 

上面的代碼是當我們在輸入框松開鍵盤之后就更新視圖模型。

對於下拉選擇,我們可以像下面這樣

<select data-role="dropdownlist" data-option-label="Select product..." data-value-primitive="true"
  data-value-field="id" data-text-field="name" data-bind="value: selectedProductId, source: products">
</select>
<script>
var viewModel = kendo.observable({
    selectedProductId: null,
    products: [
        { id: 1, name: "Coffee" },
        { id: 2, name: "Tea" },
        { id: 3, name: "Juice" }
    ]
});

kendo.bind($("select"), viewModel);
</script>

 

visible:

  與invisible類似,功能相反。

 

 

小結:

    MVVM解耦了視圖與模型,我們只需要在模型中寫好邏輯即可。這種模式簡化了我們的開發,提高開發效率。input,select,textarea的值用value,插入html用html,文本用text,checkbox和radio用checked。

 


免責聲明!

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



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