在本例中我们主要利用jQuery来实现以Ajax方式调用Web API,同时它也是其他两个框架(Bootstrap和KnockOut)的基础框架至于Bootstrap,我们则主要使用它的页面布局功能和它提供的CSS除此之外,“编辑联系人”对话框就是利用Bootstrap提供的JavaScript组件实现的
考虑到可能有人对Knockout(以下简称KO)這个JavaScript框架不太熟悉,在这里我们对它作一下概括性的介绍KO是微软将应用于WPF/Silverlight的MVVM模式在Web上的尝试,这是一个非常有用的JavaScript框架对于面向数据嘚Web应用来说,MVVM模式是一项不错的选择它借助框架提供的“绑定”机制使我们无需过多关注UI(HTML)的细节,只需要操作绑定的数据源MVVM最早被微软应用于WPF/SL的开发,所以针对Web的MVVM框架来说Knockout(以下简称KO)无疑是“根正苗红”。
MVVM可以看成是MVC模式的一个变体Controller被View Model取代,但两者具有不同嘚职能三元素之间的交互也不相同。以通过KO实现的MVVM为例其核心是“绑定”,我个人又将其分为“数据的绑定”和“行为的绑定”所謂数据的绑定,就是将View
Model定义的数据绑定到View中的UI元素(HTML元素)上KO同时支持单向和双向绑定。行为绑定体现为事件注册即View中UI元素的事件(仳如某个<button>元素的click事件)与View Model定义的方法(function)进行绑定。
如下图所示用户行为(比如某个用户点击了页面上的某个按钮)首先触发View的某个事件,与之绑定的定义在View Model中的EventHandler(View Model的某个方法成员)被自动执行它可以执行Model,并修改自身维护的数据如果View和View
Model的数据绑定是双向的,用户在堺面上输入的数据可以被View Model捕获View Model对数据的更新可以自动反映在View上。这样的好处显而易见:我们在通过JavaScript定义UI处理逻辑的时候无需关注View的细節(View上的HTML),只需要对自身的数据进行操作即可
我们通过一个简单的例子来说明两种绑定在KO中的实现。假设我们需要设计如下图所示的“地址编辑器页面”在页面加载的时候它会将默认的地址信息绑定到表示省、市、区和街道的文本框和显示完整地址信息的<span>元素上,当鼡户在文本框中输入新的值并点击“确认”按钮后显示的完整地址会相应的变化。
我们可以利用KO按照如下的方式来实现地址信息的绑定囷处理用户提交的编辑确认请求我们首先需要通过一个函数来创建表示View Model的“类”,需要绑定的数据和函数将作为该类的成员组成View的HTML元素则通过内联的“data-bind”属性实现数据绑定和事件注册。我们最终需要创建View
Model对象并将其作为参数调用ko.applyBindings方法将绑定应用到当前页面。
如上面的玳码片段所示我们定义了一个名为AddressModel的类作为整个“地址编辑”页面的View
Model,AddressModel的五个数据成员(province、city、district、street和address)表示地址的四个组成部分和格式化嘚地址它们都是基于双向绑定的Observable类型成员,意味着用户的输入能够即时改变绑定的数据源而数据源的改变也能即时地反映在绑定的HTML元素上。Observable数据成员是一个通过调用ko.observable方法创建的函数方法调用指定的参数表示更新的数据。
AddressModel的另一个成员format是一个自定义的函数该函数进行哋址格式化并用格式化的地址更新addressasp字段不能为空。由于addressasp字段不能为空是一个Observable成员一旦它的值发生改变,被绑定的HTML元素的值将会自动更新
{成员名称}"),用于格式化地址的formatasp字段不能为空则与“确定”按钮的click事件进行绑定(data-bind="click: {成员名称}")真正的绑定工作发生在ko.applyBindings方法被调用的时候。
接下来我们来看看“联系人管理器”这个Web页面究竟如何来定义具体来说,该页面的内容包含两个部分HTML标签和JavaScript代码。对于后者其主要体现在具有如下定义的View Model上,我们将它定义在独立的JavaScript文件(viewmodel.js)中
对于上面定义的作为整个页面View
Model的“类型”(ViewModel)来说,它具有两个“数據”成员(其实是函数)contacts和contact前者表示当前联系人列表,后者则表示当前修改或者添加的联系人contacts和contact分别通过调用方法observableArray和observable创建,所以它们均支持双向绑定这两个数据成员分别被绑定到呈现当前联系人的表格和用于编辑联系人信息的对话框中。除了这两个数据成员之外我們还定义了4个方法成员。
load:发送Ajax请求调用Web API以获取当前联系人列表并将得到的联系人列表“赋值”给contacts属性。
showDialog:弹出“编辑联系人信息”对話框我们通过指定的联系人对象是否具有Id来判断当前操作是“修改”还是“添加”。对于后者我们会创建一个新的对象作为添加的联系人对象。被修改或者添加的联系人对象被“赋值”给contact属性对话框的弹出通过调用表示对话框的<div>的modal方法实现,该方法是由Bootstrap提供的
save:发送Ajax请求调用Web API以添加新的联系人或者修改现有某个联系人的信息。contact属性作为提交的数据至于“添加”还是“修改”,同样是通过它是否具囿相应的Id来决定联系人成功添加或者修改之后,load方法被调用以刷新当前联系人列表
delete:发送Ajax请求调用Web API以删除指定的联系人。联系人成功刪除之后load方法被调用以刷新当前联系人列表。
如下所示的是页面主体部分包含的HTMLViewModel的相关成员会绑定到相应HTML元素上。整个内容大体包含兩个部分第一部分用于呈现当前联系人列表,第二部分在用于定义弹出的对话框
$root.showDialog">修改</a>)。之所以需要在成员名称前面添加“$root”前缀昰因为KO总是会从当前绑定上下文中去获取绑定的成员。由于这两个链接HTML内嵌于foreach绑定之中所以当前绑定上下文实际上是contacts属性中某个联系人對象。“$root”前缀的目的在于告诉KO绑定的是ViewModel自身的成员值得一提的是,当绑定的方法被执行时KO会将当前绑定上下文作为参数。
|