(更新)knockout学习-1.0

来源:互联网 发布:手机股市行情软件下载 编辑:程序博客网 时间:2024/05/17 08:57

一、konckout简介

应用MVVM模式

1、四大重要概念:

(1)声明式绑定:declarative bindings 使用简明易读的语法,将模型model数据关联到dom元素上。

(2)UI界面自动刷新:automatic ui refresh 当模型状态model state改变时,ui界面自动更新。

(3)依赖跟踪:dependency tracking 为转变和联合数据,在模型数据之间隐士建立关系。

(4)模板:templating 为模型数据快速编写复杂的可嵌套的UI。


2、入门介绍

 以数据模型data model为基础,相应显示和编辑用户界面的js类库。UI更新依赖于用户的行为或者外部数据源的改变,ko可以快速实现且容易维护。

可以把KO当成通过编辑json数据来制作ui用户界面的方式。

特性:

数据模型更新——自动更新相应内容。

声明式绑定——将用户界面指定部分关联到数据模型上。

模板——嵌套模板构建复杂的动态界面。

扩展——自定义行为作为新的声明式绑定。


3、使用

    (1)声明你的数据作为一个js模型对象(model object)。

    (2)将dom元素或者模板(templates)绑定到它上面。

    (3)启用kockout使绑定生效。

   ko.observable——a、ui可以监控这个的值,并回应它的变化。

                                    b、 首先对它初始化。

                                    c、其次将其关联到dom上,告诉dom元素的text/value/options等属性中的一个:读取/写入这个ko.observable,它对应的是要绑定的view model的属性。

如:

var viewmodel = {

chosenMeal: ko.observable(初始值)

}

对应html 中:<select data-bind="value:chosenMeal"></select> //即将chosenMeal这个view model中 可观测(ko.observable)的值关联到dom上了。告诉dom可以读取/写入这个可观测的值了。

完整例子1:

<!DOCTYPE HTML>
<html>
<head>
    <title></title>
    <script type="text/javascript" src="js/knockout-3.1.0.js"></script>
    <style type="text/css">
    </style>
</head>
<body>
    <!-- 2、把数据绑定到DOM:下拉菜单上。每个option选项为:options,对应的是声明的数据availableMeals。option的文本——用引号——内容,对应的是'mealName'-->
    <h2>meal upgrades</h2>
    <!--这里面只有chosenMeal是可观测的,它是ko.observable,是applyBingds()绑定的参数——viewModel的属性。(chosenMeal对应的又是声明的数据aMeal数据。即aMeal变化,chosenMeal自动更新)-->
    chosen meal:<select data-bind="options:aMeals,optionsText:'mealName',value:chosenMeal"></select>
    <!--相应选择,在dom上绑定可观测值。ko.observable一般是一个函数对象,对应可取它的属性。-->
    <p data-bind="text: format(chosenMeal().extraCost)"></p>
</body>
<script>
    // 1、声明数据
    var aMeals = [
        {mealName:'standar',description:'crusts of bread',extraCost: 0},
        {mealName:'premium',description:'fresh bread',extraCost: 20.5},
        {mealName:'deluxe',description:'peppers',extraCost: 600}
    ];
    
    // 2、把数据绑定到DOM:下拉菜单上。用data-bind到select上,定义option的表示内容和显示的文本。见html

    // 4、可观测值的声明。javascript对象 var object={};
    // 4.1 初始化——声明简单的data model数据模型描述已经选择的下拉选项。添加一个属性到当前view model上面。
    var viewModel = {
        chosenMeal: ko.observable(aMeals[1])
    };
    // 4.2 响应选择。把这个可观测值ko.observable绑定到dom上。见html


    // 3、启用kockout使绑定生效
    ko.applyBindings(viewModel);

    //其他:将价格格式化带有$符号
    function format(price) {
        return price == 0 ? "free": "$" + price.toFixed(2); 
    }
</script>
</html>


上面的例子中:

每个下拉数据的名字,值,价格作为一个aMeal对象,是ko.observable(viewModel)中参数可观测对象——vieModel的属性,即aMeal对象是可观测的。

当下拉选项的数据——与js中已经声明的数据绑定,进行显示。

                                        当下拉选项的数据改变时——aMeal对象数组中在界面显示的对象改变,三组数据中显示一组——>显示的那一组其对应的value绑定值:chosenMeal:ko.observable(aMeals[1])这个参数——可观测值也跟着改变。——><p></p>绑定的chosenMeal改变,chosenMeal的属性extraCost跟着改变。


 var viewModel = {
        chosenMeal: ko.observable(aMeals[1])    // 只是初始化,这个可观测的括号中的参数,在界面中是根据操作不同显示不同的,是可观测到的,是一个变化的值。当下拉框选择第一项时,这个可观测值就变成了aMeals[0]
    };


3、mvvm andviewmodel

将用户界面分成三个部分:

(1)model 存储的数据,模型数据。

(2)view model 在UI上,数据及操作。包含列表项和对列表项的操作。

(3)view 从view model显示数据,发送命令到view model,随着view model跟新而更新。——带有绑定的html。

创建一个view model,对其初始化,声明一个js object即可。

如:

var viewModel ={};

或:var viewModel = { name:'abc', age:123};里面列出属性-值对

可以直接在html中声明绑定其属性。


激活konckout

ko.applyBindings(myViewModel);




二、监控属性

1、创建带有监控属性的view model

kockout的核心功能:

(1)监控属性:observables

          依赖跟踪:dependency tracking

(2)声明式绑定:declarative bindings

(3)模板:templating


不是所有浏览器都支持js的设置和获取,所以为了兼容性,使用ko.observable监控的对象都是真实的function函数。

var viewmodel ={name:ko.observable('abc'),age:ko.observable(123)};

读取监控属性:viewmodel.name()要带上括号。因为observable监控到的对象name和age都是function。

不是观测值,比如是数据模型中的属性就不需要带上括号了,因为不是function。


2、监控属性observable的显示订阅

viemodel.name.subscribe(function(){});

终止订阅:var subscription = viemodel.name.subscribe(function(){}); subscription.dispose();


UI监测js中的值。

js将其值绑定到UI的dom上面,告诉ui的元素可以读写js中的模型属性,进行这个绑定地方的初始化。

这就是在viewModel中可以初始化select的显示第几个元素的原因。

因为select的data-bind是chosenMeal,ui在js中监测查找到这个可观测值ko.observable,在js中找到这个view model 模型中的该属性,进行读写,完成初始化,对应在ui界面上完成初始化显示。



流程:声明数据——UI监测要绑定的ko.observable:在html中将要观测的值绑定到dom上面;在js中在对dom中对应的可观测值完成读写,实现界面初始化——激活knockout绑定——ui界面手动操作改变显示内容,对应绑定的内容替换。其他绑定位置也同步更新。

响应选择

声明一个简单的data model来描述旅客已经选择的套餐,添加一个属性到当前的view model上:

var viewModel = {    chosenMeal: ko.observable(availableMeals[0])};

ko.observable是什么?它是KO里的一个基础概念。UI可以监控(observe)它的值并且回应它的变化。这里我们设置chosenMeal是UI可以监控已经选择的套餐,并初始化它,使用availableMeal里的第一个值作为它的默认值(例如:Standard)。

让我们将chosenMeal 关联到下拉菜单上,仅仅是更新<select>的data-bind属性,告诉它让<select>元素的值读取/写入chosenMeal这个模型属性:

Chosen meal: <select data-bind="options: availableMeals,                                optionsText: 'mealName',                                value: chosenMeal"></select>



3、使用依赖监控属性

 JavaScript 对象没有任何办法能引用他们自身,所以你需要通过myViewModelObject.myDependentObservable = ... 的形式添加依赖监控属性到view model对象上。不能直接在view model里声明他们,换句话说,你不能写成下面这样:

var viewModel = {    myDependentObservable: ko.dependentObservable(function() {        ...    }, /* can't refer to viewModel from here, so this doesn't work */)}
而是:

var viewModel = {    // Add other properties here as you wish};

viewModel.myDependentObservable = ko.dependentObservable(function() {
...}, viewModel);

4、依赖跟踪如何工作的

新手没必要知道太清楚,但是高级开发人员可以需要知道为什么依赖监控属性能够自动跟踪并且自动更新UI…

事实上,非常简单,甚至说可爱。跟踪的逻辑是这样的:

  1. 当你声明一个依赖监控属性的时候,KO会立即调用执行函数并且获取初始化值。
  2. 当你的执行函数运行的时候,KO会把所有需要依赖的依赖属性(或者监控依赖属性)都记录到一个Log列表里。
  3. 执行函数结束以后,KO会向所有Log里需要依赖到的对象进行订阅。订阅的callback函数是重新运行你的执行函数。然后回头重新执行上面的第一步操作(并且注销不再使用的订阅)。
  4. 最后KO会通知上游所有订阅它的订阅者,告诉它们我已经设置了新值。

所有说,KO不仅仅是在第一次执行函数执行时候探测你的依赖项,每次它都会探测。举例来说,你的依赖属性可以是动态的:依赖属性A代表你是否依赖于依赖属性B或者C,这时候只有当A或者你当前的选择B或者C改变的时候执行函数才重新执行。你不需要再声明其它的依赖:运行时会自动探测到的。

另外一个技巧是:一个模板输出的绑定是依赖监控属性的简单实现,如果模板读取一个监控属性的值,那模板绑定就会自动变成依赖监控属性依赖于那个监控属性,监控属性一旦改变,模板绑定的依赖监控属性就会自动执行。嵌套的模板也是自动的:如果模板X render模板 Y,并且Y需要显示监控属性Z的值,当Z改变的时候,由于只有Y依赖它,所以只有Y这部分进行了重新绘制(render)。

5   使用observable数组

如果你要探测和响应一个对象的变化,你应该用observables。如果你需要探测和响应一个集合对象的变化,你应该用observableArray 。在很多场景下,它都非常有用,比如你要在UI上需要显示/编辑的一个列表数据集合,然后对集合进行添加和删除。

关键点:监控数组跟踪的是数组里的对象,而不是这些对象自身的状态。

简单说,将一对象放在observableArray 里不会使这个对象本身的属性变化可监控的。当然你自己也可以声明这个对象的属性为observable的,但它就成了一个依赖监控对象了。一个observableArray 仅仅监控他拥有的对象,并在这些对象添加或者删除的时候发出通知。

预加载一个监控数组observableArray

如果你想让你的监控数组在开始的时候就有一些初始值,那么在声明的时候,你可以在构造器里加入这些初始对象。例如:

var anotherObservableArray = ko.observableArray([    { name: "Bungle", type: "Bear" },    { name: "George", type: "Hippo" },    { name: "Zippy", type: "Unknown" }]);

从observableArray里读取信息

一个observableArray其实就是一个observable的监控对象,只不过他的值是一个数组(observableArray还加了很多其他特性,稍后介绍)。所以你可以像获取普通的observable的值一样,只需要调用无参函数就可以获取自身的值了。

下面讲解的均是observableArray的读取和写入的相关函数。

indexOf

indexOf 函数返回的是第一个等于你参数数组项的索引。例如:myObservableArray.indexOf('Blah')将返回以0为第一个索引的第一个等于Blah的数组项的索引。如果没有找到相等的,将返回-1。

slice

slice函数是observableArray相对于JavaScript 原生函数slice的等价函数(返回给定的从开始索引到结束索引之间所有的对象集合)。 调用myObservableArray.slice(...)等价于调用JavaScript原生函数(例如:myObservableArray().slice(...))。

 

操作observableArray

observableArray 展现的是数组对象相似的函数并通知订阅者的功能。

pop, push, shift, unshift, reverse, sort, splice

所有这些函数都是和JavaScript数组原生函数等价的,唯一不同的数组改变可以通知订阅者:

    myObservableArray.push('Some new value') 在数组末尾添加一个新项

    myObservableArray.pop() 删除数组最后一个项并返回该项

    myObservableArray.unshift('Some new value') 在数组头部添加一个项

    myObservableArray.shift() 删除数组头部第一项并返回该项

    myObservableArray.reverse() 翻转整个数组的顺序

    myObservableArray.sort() 给数组排序

        默认情况下,是按照字符排序(如果是字符)或者数字排序(如果是数字)。

        你可以排序传入一个排序函数进行排序,该排序函数需要接受2个参数(代表该数组里需要比较的项),如果第一个项小于第二个项,返回-1,大于则返回1,等于返回0。例如:用lastname给person排序,你可以这样写:myObservableArray.sort (function (left, right) {return left.lastName == right.lastName? 0: (left.lastName < right.lastName? -1: 1) })

     myObservableArray.splice() 删除指定开始索引和指定数目的数组对象元素。例如myObservableArray.splice(1, 3) 从索引1开始删除3个元素(第2,3,4个元素)然后将这些元素作为一个数组对象返回。

更多observableArray 函数的信息,请参考等价的JavaScript数组标准函数。

 

remove和removeAll

observableArray 添加了一些JavaScript数组默认没有但非常有用的函数:

    myObservableArray.remove(someItem) 删除所有等于someItem的元素并将被删除元素作为一个数组返回

    myObservableArray.remove(function(item) { return item.age < 18 }) 删除所有age属性小于18的元素并将被删除元素作为一个数组返回

    myObservableArray.removeAll(['Chad', 132, undefined]) 删除所有等于'Chad', 123, or undefined的元素并将被删除元素作为一个数组返回

 

destroy和destroyAll(注:通常只和和Ruby on Rails开发者有关)

destroy和destroyAll函数是为Ruby on Rails开发者方便使用为开发的:

    myObservableArray.destroy(someItem) 找出所有等于someItem的元素并给他们添加一个属性_destroy,并赋值为true

    myObservableArray.destroy(function(someItem) { return someItem.age < 18 }) 找出所有age属性小于18的元素并给他们添加一个属性_destroy,并赋值为true

    myObservableArray.destroyAll(['Chad', 132, undefined]) 找出所有等于'Chad', 123, 或undefined 的元素并给他们添加一个属性_destroy,并赋值为true

 

那么,_destroy是做什么用的?正如我提到的,这只是为Rails 开发者准备的。在Rails 开发过程中,如果你传入一个JSON对象,Rails 框架会自动转换成ActiveRecord对象并且保存到数据库。Rails 框架知道哪些对象以及在数据库中存在,哪些需要添加或更新, 标记_destroy为true就是告诉框架删除这条记录。

 

注意的是:在KO render一个foreach模板的时候,会自动隐藏带有_destroy属性并且值为true的元素。所以如果你的“delete”按钮调用destroy(someItem) 方法的话,UI界面上的相对应的元素将自动隐藏,然后等你提交这个JSON对象到Rails上的时候,这个元素项将从数据库删除(同时其它的元素项将正常的插入或者更新)。




0 0