Knockout.js入门
Knockout.js是一个JavaScript库,它可以让你声明绑定元素和其对应的数据模型,达到你的UI和模型自动双向更新。Knockout入门不难,并且它很好地集成了其他的类库和技术。通过本篇文章你可以入门。
为什么是Knockout
开发一个复杂的、动态的以数据驱动的(data-driven数据驱动)网页应用是一个具有挑战的任务。当用户进行操作、或新的数据被加载时,保持用户界面与底层数据正常同步,涉及到关联大量的事件来控制各种元素与数据的中间数据信息。
Knockout之前
用一个简单的方法来证明Knockout的优势,重要的是了解如何使用Knockout创建简单的编辑器,和不用Knockout是如何创建的。
<div id="itemName"></div>
<input type="text" id="itemNameEdit" />
使用jQuery,你可以关联一组数据和他们对应数据的交互,如下:
var item = {
id: 88,
name: "Apple Pie"
};
$("#itemName").text(item.name);
$("#itemNameEdit").val(item.name).change(function() {
item.name = $(this).val();
$("#itemName").text(item.name);
});
这些代码没有什么难度,但是对于一个应用,需要管理的UI和数据的交互会越来越多,这类代码会持续增加,直到很难维持。此外,这种类型的代码是通过设置特定标识紧密耦合的,很难重用。
添加一些数据绑定
Knockout可以让你通过你的标识使用声明将你的UI和数据轻松关联绑定。在一般情况下,你的元素不再需要ID和类,除非用于样式。Knockout的绑定中,指定data-bind属性到一个单独的元素上:
<div data-bind="text: name"></div>
<input type="text" data-bind="value: name" />
现在那些元素被指定绑定,你需要命令Knockout获取你的数据并应用到这些元素上,使用ko.applyBindings函数。
var item = {
id: 88,
name: "Apple Pie"
};
ko.applyBindings(item);
在这里,这个div会显示 "Apple Pie",并且在编辑修改input时保存到你的item里的name属性里。可是,这个更新不会导致你的div自动更新。要使这些更新引起注意,name属性需要使用Knockout的一个重要架构,observable会创建一个关注点(observable),name属性需要包到ko.observable函数里并执行。
var item = {
id: 88,
name: ko.observable("Apple Pie")
};
ko.applyBindings(item);
现在,当name关注点有变化时这个div会被更新。数据绑定自动订阅所有关注点,并且每当它们被通知更新时,可以适时更新它们的DOM元素。你也可以在订阅的关注点变化时进行编程,执行额外的逻辑,比如把数据传回服务器。
使用MVVM模式(Model-View-View-Model)
Knockout允许你为你的交互使用MVVM模式架构。这个模式通过保持几个不同层次的分离,描述如何管理复杂的功能。
模型(Model)
这个模型代表你的应用数据。Knockout没有专门处理从后端服务器返回的中间数据的功能,让你来决定使用最好的方法来实现。特定的后端技术对于Knockout并不重要,只要你可以在你的JavaScript代码里访问你的数据。常用的方法有以下几个:
- 使用AJAX请求服务器发送和接收数据
- 序列化数据直接到页面脚本块
- 在适当的时候,使用静态数据,通常从一个外部JavaScript文件加载
- 在某些情况下,甚至从一个呈现的内容创建一个视图模型,使用自定义绑定
视图(View)
view代表你的标识,可以真正被当作一个模板来渲染对应你的视图模型。对于一个健壮的视图模型,视图应真正地获得所有的那些需要使用简单的声明绑定对应的视图模型可见的概念。如果你发现你的绑定需要包含复杂的逻辑或者程序达到正确的结果,那么,这是好的迹象,视图模型没有结构化,在某种意义上这是最好的视图架构。
视图模型(View model)
View model是你的应用的心脏。它是你的用户界面的代码式描述,它包括数据和相关用于处理数据的行为。视图模型的目标是为视图和相应绑定提供一个易于理解的结构。它可能包括过滤(filtered)、排序(sorted),和模型版本的操作数据,还有潜在的额外元数据或概念,涉及到用户界面操作。例如,你可能会跟踪item的可见性和可编辑性,但是不保存这个信息到数据库。
在一个理想的Knockout应用里,你的视图模型包含非引用到DOM元素、选择器(selectors),或任何的绑定视图的知识点。这种分离带来了些不错的优势:
- 视图模型就其本身而言,很容易,不包含UI
- 你可以正常重构你的标识而不必担心破坏选择器。你确定绑定是否仍然合适,但是他们直接列出你正在移动的元素。
- 一个简单的视图模型可以用于多个视图。一个常见的例子是渲染一个简单的item视图,对比处理items集合。在某些情况下,你也可以渲染另一种移动视图,共享相同视图模型代码。
Knockout核心结构
在JavaScript中,设置属性值本身不能通知任何人它被改变了。为了支持这种需求,Knockout创建了几个结构,他们的功能是跟踪订阅和当有变化时执行。当底层数据有变化时,绑定被触发,并适时地更新到DOM元素。
关注点Observables
Knockout的基本结构是方便跟踪和改变,被称为observable。你通过调用ko.observable()创建observable。一个observable实际上是一个缓存了当前值的函数。要恢复一个observable的值,你可以调用一个不带参的函数。设置一个值,你通过一个简单的参数来为observable设置一个新值:
this.name = ko.observable("Apple Pie");
alert(this.name()); //读一个值
this.name("Pumpkin Pie"); //设置一个值
动态关注点(Computed observables)
Knockout也支持Computed observables,作为一种动态值——当绑定的对象发生改变时,值永远保持更新:
this.formattedName = ko.computed(function() {
return this.id + " - " + this.name();
}, this);
当一个动态observable被创建时,它将缓存它现在的值当它的绑定对象更新时仅重新估算。一个动态observable通过跟踪每一次重新估算得到的值来声明动态绑定。这意味着你不需要为那些值指定更新完成时的绑定,并且估算逻辑仅需要在绑定有变化时才运行。
Observable数组(ObservableArrays)
大多数应用程序处理一个或多个数据集合。Knockout包含ObservableArrays来支持数据数组,当UI需要知道items是被添加或被移除。ko.observableArray只是一个可见的、包括额外处理普通数组操作的函数。当操作一个ObservableArrays,底层数组被更新,然后通知相关订阅数组已经改变。
内置绑定(Built-in bindings)
绑定是神奇的,它关联你的标识与你的视图模型。Knockout包含常见用例的绑定,也允许你使用自定义函数进行扩展。表1-3总结了Knockout支持的绑定:
Knockout扩展
Knockout的指导原则之一就是坚持自己的优点并提供它核心能力之外功能的可扩展。这使得你可以将Knockout作为首选的类库和技术。为了最大化地使用Knockout,你应该了解Knockout提供的各种扩展项。
自定义绑定
Knockout让你轻松地创建自己的绑定,这也是最常用的扩展项。当你需要编写触发两个数据和DOM元素的代码时,使用内置绑定无法做到,那么你可能想创建一个自定义绑定。
所有的绑定(自定义和内置)都源自ko.bindingHandlers对象。每个绑定是一个对象,可以选择生成一个init的函数,当绑定被第一次被执行时运行,一个updata函数,当它的绑定有一个或更多发生变化时运行。
扩展Knockout的核心结构
Knockout也允许你扩展前面讲过的核心结构。这创造了一个有吸引力的机会——创建可重用的功能,可以让你的视图模型代码更干净、简洁。
Knockout的核心类型所有常用的函数都源自他们的fn对象,即ko.observable.fn。所以,任何你添加到ko.observable.fn的函数对所有的observables都是有效的。更多的关于类型层次结构的信息请看Knockout官方网站的Adding custom functions using "fn" (使用"fn"添加自定义函数)。
其他可扩展项
Knockout也包括其他一些值得注意的扩展项。
模板母版:Knockout有可供选择使用的模板母版,在template(模板)绑定中。一个基本的模板母版可被扩展,定制一个如何将数据和模板执行声明生成标识达到绑定。
模板源码:你可以定制Knockout如何声明模板主体。这需要你下载模板,来源于外部源码或商店模板。
绑定供应:你可以重写Knockout如何声明每一个元素被绑定,和这些绑定如何被转化。这个意味着你可以重置data-bind属性,通过你自己的结构。一个可供选择的绑定供应,它允许你在代码中指定绑定并从已经下载的标识中嵌进去,在我的knockout-classBindingProvider GitHub project中和Knockout 1.3 preview blog post中描述如何建立一个绑定供应。
原文连接:http://bbs.9ria.com/forum.php?mod=viewthread&tid=173045&page=1#pid1663279