• 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。

  • 相关阅读:
    checkbox 实现单选效果(html)
    HDU-6850 Game
    牛客练习赛29----F 算式子
    牛客多校第二场 B Boundary
    D. Omkar and Circle
    【洛谷】P3306 [SDOI2013]---- 随机数生成器
    二次剩余
    【洛谷】--P2704 [NOI2001]炮兵阵地
    【洛谷】4310 绝世好题
    快速排序
  • 原文地址:https://www.cnblogs.com/xiyangbaixue/p/4168832.html
Copyright © 2020-2023  润新知