最近马上要开始一个新项目的研发,作为第一次mvvm应用的尝试,我决定使用knockoutjs框架。作为学习的开始就从官网的Document翻译开始吧,这样会增加印象并加入自己的思考,说是翻译也并不是纯粹的翻译,会加入自己对知识点的思考以及自己的尝试,在系列最后也希望用一个应用案例作为结尾。希望自己能坚持下来并有所收获,理解不对的地方大家也指出来避免我”误入歧途“。也并不会翻译所有的内容,我会根据自己的经验选择最能反映它使用和精髓的部分。当前版本为3.4

好了,闲言少叙,正篇开始。

  

  ===================================华丽的分割线============================================

knocket主要围绕由以下三个核心特征组成:

  1. Observables(观察器)与dependency tracking(依赖追踪)
  2. Declarative bindings(声明式绑定)
  3. Templating(模板)

MVVM and View Models

Model-View-View Model (MVVM) 是一种创建用户界面或用户接口的设计模式。你可以通过将UI拆分成下面三个部分从而将复杂的UI简洁化,清晰化:

  • Model(数据模型): 应用程序存储数据。模型包括了你应用程序域中与业务相关的数据以及这些数据对应的操作(例如 一个银行账户模型具有转账的功能)并且它跟UI是相互独立 的。 当时用KO的时候,通常这类模型是通过ajax从服务器端进行获取的。
  • ViewModel(视图模型): 服务于数据模型,为数据模型在UI上的展现及UI上的操作进行包装服务。 例如, 如果你要在UI上做一个列表展现, 你的视图模型将会是包含一个数据集合的对象, 并提供一些添加和删除数据的相关方法。需要注意的是视图模型并不是UI本身,它并不包括任何UI元素,比如按钮啊,标签啊样式之类。它也不是持久化的数据对象,它只是为数据模型临时保存一些用户正在处理的数据。当我们在使用KO的时候,它无非就是一些纯粹的javascript对象而已。
  • view(视图): 一个可视,可交互的真正的UI展现,他展现着视图模型的当前状态。它所展现的信息来自于视图模型,并且向视图模型发送命令执行动作 (例如: 当用户点击按钮的时候,视图向视图模型发送命令,视图模型进行真正的操作),并且当视图模型属性发生变化的时候,视图会自动进行展现的更新。当时用KO的时候,你的视图中的Html元素内容可以通过声明式绑定与视图模型进行连接从而决定UI如何展现。另外,你也可以通过使用模板的方式来使用视图模型中的数据生成UI中的Html内容。(模板后面会提到)

好了,让我们来举个很小的例子来看看上面说的视图与视图模型在KO中是如何协作的。创建一个视图模型对象非常容易,随意声明一个javascript对象我们就可以将它作为视图模型对象。例如:

 //创建一个视图模型对象
var myViewModel = {
personName: 'Bob',
personAge: 123
};
ko.applyBindings(myViewModel);//ko是knockoutjs中的全局对象,这句话的意思是将数据模型对象与UI中所有有data-bind的属性进行声明绑定的元素进行连接

然后我们就可以创建一个非常简单的视图来展现上面的视图对象。还记得吗?他们使用声明式绑定来进行连接。下面的视图用来展现视图模型对象中的personName数据。

The name is <span data-bind="text: personName"></span>

好了现在如果运行页面的话将会显示如下运行结果:

通过上面的例子我们可以看到,在UI上赋值我们并没有像jquery一样通过js来控制,而是使用声明绑定的方式在UI元素和js数据对象上建立联系,自动展现。在上面的代码标签中data-bind 并不是Html中的原生标记,它在Html5中得到浏览器的支持,是KO框架用来进行声明式绑定的工具,所以在KO中进行声明式绑定,都通过data-bind属性进行。有了视图模型,有了相应视图,最后要进行两者的连接了,所以下面这行代码必不可少:

ko.applyBindings(myViewModel); //将myViewModel对象与UI中所有进行了声明式绑定的元素进行连接,注意:是所有。

完整测试代码:

The name is <span data-bind="text: personName"></span>
@section scripts
{
<script src="~/Scripts/knockout-3.4.0.js"></script>
<script type="text/javascript"> $(function () {
var myViewModel = {
personName: 'Bob',
personAge: 123
};
ko.applyBindings(myViewModel);
});
</script>
}

关于ko.appyBindings(myViewModel)中参数的作用说明一下:第一个参数说明在整个UI中你希望使用哪个视图模型对象与视图中的声明绑定进行连接。你也可以传递第二个参数来决定这个视图模型与UI中的哪个特定的声明式绑定(data-bind)进行连接,而不是与所有的进行连接。举个例子, ko.applyBindings(myViewModel, document.getElementById('someElementId'))。这就限制了这个视图模型对象只能与ID为someElementId 的Html元素对象以及它的后代元素对象进行连接,这样的话当你想要定义多个视图模型对象并且与页面中不同的元素进行绑定的时候就会特别有用。到目前为止真的是相当简单吧。

   Observables

好了,你已经看到了如何创建一个基本的视图模型以及如何通过绑定进行它的属性数据的展现。但是使用KO一个核心的好处是当视图模型内容改变的时候它还会自动更新你的UI,反之亦然。这有时会大大简化你的代码(我们稍后展示这个效果)。那么KO如何知道你的视图模型什么时候发生了改变进而更新你的UI呢?答案是:你需要将你的数图模型中的属性声明为observable类型对象。 observables类型对象非常特殊,当视图模型发生改变的时候,他们可以向订阅者发出通知,并自动建立与订阅者的关系,订阅者也就是具有声明式绑定的元素。举个例子, 重写一下上面的代码如下:

$(function () {
var myViewModel = {
personName: ko.observable('Bob'),
personAge: ko.observable(123)
};
ko.applyBindings(myViewModel);
});

现在,你完全不需要视图 data-bind 声明部分保持不变. 与之前代码不同的是,现在ko可以自动监测变化了, 一旦视图模型有数据发生变化,它就会自动更新视图。

Observables属性的读取与写入

     要读取observable的当前值,只需要像调用方法一样以无参数的方式调用它。以上面的代码为例, myViewModel.personName() 将会返回 'Bob',而myViewModel.personAge() 将返回123。

要向observable属性中写入一个值的话也跟上面一样进行调用,只不过传入一个你想要写入的新值就可以了。举个例子:调用myViewModel.personName('Mary') 将会为personName赋一个新的名字。另外KO还提供了一个非常方便的代码链写法。 像这样:myViewModel.personName('Mary').personAge(50) 会修改personName为 'Mary' ,personAge修改为 50。

observables的核心作用就是"观察" ,也就是说, 被声明为observable的属性将来是会被双向通知的,它通知其它UI元素它已经被修改了,并且观察相关UI元素内容,并将变化值更新到ViewModel对象上。KO框架中的很多内置绑定就是用来干这事儿的。所以,当你在UI元素上(例如span标签)写上data-bind="text: personName"的时候 text 绑定类型将把这个span元素进行注册并做好被通知的准备只要视图对象上的personName发生了该表,span就会被通知修改内部的文本内容(假设personName是一个observable值,另外除了text绑定还有许多其它类型绑定,我们后面提到)。

当你通过调用myViewModel.personName('Mary')来修改personName的值的时候, text绑定将会自动更新相关DOM元素的text内容 。

observables的显示订阅处理

    通常你无需干预订阅的过程,所以初学者可以暂时跳过这一小节。

当observable类型数据发生改变后如果你希望在这个过程中做一些处理,你可以调用observable属性上的subscribe方法来将自己的处理代码注册进来。举个例子:

myViewModel.personName.subscribe(function(newValue) {
alert("The person's new name is " + newValue);
});

上面这段代码执行后,如果修改了personName的值后,那么将会弹出一个警告框,并且通过newValue参数可以获取当前正在更新的值。这个过程叫订阅注册。

subscribe方法接受三个传入参数callback 是一个function当通知到来时会自动执行, target (可选) 定义了在callback方法中 this代表了哪个对象(默认的话this就是当前视图模型对象), event(可选; 默认值是"change") 事件名称,是指当什么类型的事件发生的时候会有通知到来,默认情况下就是当值发生改变的时候。(其它类型我们后面谈到)。

当然了,一旦你注册了一个自己的订阅,你也可以根据需要在未来的某个时候取消这个订阅,你需要先定义一个变量来接收subscribe当前的返回值,然后调用dispose方法。代码如下

var subscription = myViewModel.personName.subscribe(function (newValue) { /* do stuff */ });
// ...then later...
subscription.dispose();

如果你希望在observable类型值在发生改变,但被赋值之前做一些处理的话,你也可以在beforeChange 事件上注册自己的处理,代码如下:

myViewModel.personName.subscribe(function(oldValue) {
alert("The person's previous name is " + oldValue);
}, null, "beforeChange");

注意: Knockout 是否触发上面的订阅还有一个默认条件就是新的值必须与老的值不相同,如果赋值时是相同值的话那么将不会触发这两个订阅。如果需要更改这种默认动作可以使用订阅器上的extend方法来修改。代码如下:

myViewModel.personName.extend({ notify: 'always' });

最后,如果你的observable属性在更新时的动作比较耗时或者会更新的很频繁,你可以通过限制通知的时间间隔,毕竟订阅通知会有性能影响。做法如下:

myViewModel.personName.extend({ rateLimit: 50 });

这样的话就算是频繁更新属性值,每次通知的事件间隔也会控制在50毫秒。测试代码如下:

<button type="button" id="btnStart">点击测试</button>
<span id="clickcontent"></span>
@section scripts {
<script src="~/Scripts/knockout-3.4.0.js"></script>
<script type="text/javascript"> $(function () { var myViewModel = {
//personName: ko.observable("ZhouBo")
personName: ko.observable("ZhouBo")
};
myViewModel.personName.extend({ notify: 'always' });
myViewModel.personName.extend({ rateLimit: 5000 }); ko.applyBindings(myViewModel); var index = 0; $('#btnStart').click(function () {
$('#clickcontent').text(++index);
myViewModel.personName(++index);
});
});

说明:如果我快速点击按钮 btnStart,则5秒钟之后第一个span的内容才会发生变化,也就是5庙后才发送了一次通知。

Knockoutjs官网翻译系列(一)的更多相关文章

  1. Knockoutjs官网翻译系列(四) computed中依赖追踪是如何工作的

    初学者无需了解这些 ,但是很多高级程序员想知道我们为什么可以保持跟踪这些依赖以及可以正确的更新到UI中.它其实很简单.跟踪算法是这样的: 无论何时你定义了一个computed observable,K ...

  2. Knockoutjs官网翻译系列(三) 使用Computed Observables

    书接上回,前面谈到了在视图模型中可以定义普通的observable属性以及observableArray属性实现与UI元素的双向绑定,这一节我们继续探讨第三种可实现绑定的属性类型:computed o ...

  3. Knockoutjs官网翻译系列(二) Observable 数组

    承接前文,前文书说道了KO框架中如何使用observable的视图模型属性来与UI元素进行绑定并自动进行双向更新的事儿.observable属性除了服务基础数据类型之外,还定义了专门为服务数组类型的o ...

  4. RavenDB官网文档翻译系列第一

    本系列文章主要翻译自RavenDB官方文档,有些地方做了删减,有些内容整合在一起.欢迎有需要的朋友阅读.毕竟还是中文读起来更亲切吗.下面进入正题. 起航 获取RavenDB RavenDB可以通过Nu ...

  5. 【官网翻译】性能篇(四)为电池寿命做优化——使用Battery Historian分析电源使用情况

    前言 本文翻译自“为电池寿命做优化”系列文档中的其中一篇,用于介绍如何使用Battery Historian分析电源使用情况. 中国版官网原文地址为:https://developer.android ...

  6. 【工利其器】必会工具之(三)systrace篇(1)官网翻译

    前言 Android 开发者官网中对systrace(Android System Trace)有专门的介绍,本篇文章作为systrace系列的开头,笔者先不做任何介绍,仅仅翻译一下官网的介绍.在后续 ...

  7. 卸载 Cloudera Manager 5.1.x.和 相关软件【官网翻译】

    问题导读: 1.不同的安装方式,卸载方法存在什么区别?2.不同的操作系统,卸载 Cloudera Manager Server and 数据库有什么区别? 重新安装不完整如果你来到这里,因为你的安装没 ...

  8. android測试工具MonkeyRunner--google官网翻译

    近期在复习之前的笔记,在回想MonkeyRunner时看了看google官网的内容,写得不错.就翻译出来分享下.事实上google官网真是一个学习的好地方. 基础知识 MonkeyRunner工具提供 ...

  9. Knockout.Js官网学习(系列)

    1.Knockout.Js官网学习(简介) 2.Knockout.Js官网学习(监控属性Observables) Knockout.Js官网学习(数组observable) 3.Knockout.Js ...

随机推荐

  1. delphi OnMouseLeave 事件不灵敏及解决之道(使用TrackMouseEvent函数进行加强)

    http://topic.csdn.net/t/20020104/09/456913.html CM_MouseLeave消息好象不太灵敏,当鼠标快速移出窗体时,就收不到这个消息,请问大家有什么好办法 ...

  2. Hibernate中的事务隔离

    在我们的项目中,老发现程序报告sesssion is closed或者因数据已经被其他事务修改而导致当前事务无法提交,由于系统的运行用户最多也就几十个人,所以考虑使用严格的事务隔离来防止这种类型的问题 ...

  3. Spark运行各个时间段的解释

    package org.apache.spark.ui private[spark] object ToolTips {  val SCHEDULER_DELAY =    ""& ...

  4. XFS:大数据环境下Linux文件系统的未来?

    XFS:大数据环境下Linux文件系统的未来?   XFS开发者Dave Chinner近日声称,他认为更多的用户应当考虑XFS.XFS经常被认为是适合拥有海量数据的用户的文件系统,在空间分配方面的可 ...

  5. sed删除文本第一个匹配行

    源文本如下,要求删除第一个为happy-123456的行. ----------------------------- aaaaaaa happy- bbbbbb asdasawe happy- ds ...

  6. (转载)教你在PHP中使用全局变量

    (转载)http://www.chinaz.com/program/2009/0123/64261.shtml 即使开发一个新的大型PHP程序,你也不可避免的要使用到全局数据,因为有些数据是需要用到你 ...

  7. zoj 3672 Gao The Sequence

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4915题意:a[k]-一个任意的数,这个数要等于a[1]~a[k]每个数减去任意 ...

  8. POI使用详解

    Apache POI使用详解 1.POI结构与常用类 (1)POI介绍 Apache POI是Apache软件基金会的开源项目,POI提供API给Java程序对Microsoft Office格式档案 ...

  9. Mybatis+SpringMVC实现分页查询(附源码)

    Maven+Mybatis+Spring+SpringMVC实现分页查询(附源码) 一.项目搭建 关于项目搭建,小宝鸽以前写过一篇Spirng+SpringMVC+Maven+Mybatis+MySQ ...

  10. winform combobox控件绑定 分类: WinForm 2014-04-17 14:34 118人阅读 评论(0) 收藏

    想要达到的效果:把数据库中的一列数据绑定到combobox控件中. 数据库表:T_Task//任务表 列名:Task_Name//名称 主键:Task_ID combobox控件名称:cbName 解 ...