Utilities

Knockout 提供了许多可以你开发中使用的工具,你可以在 ko.utils 命名空间中找到它们,我最喜欢的工具如下所示:

  • extend: 这个方法将两个对象合并在一起,调用这个方法之后,会将第二个对象的所有属性,方法合并到第一个对象上。
  • unwrapObservable: 这个方法获取一个属性作为参数,然后返回它的值。比如 Knockout 的 Observable 属性,或者一个简单的属性。这个函数在你希望在运行时获取对象的实际值得时候很有用。
  • 所有的数组工具:Knockout 提供了许多对于数据操作的工具,允许你过滤,映射,或者删除其中的项目。我经常在项目开始的时候,将这些方法附加到ko.observableArray.fn 上。

下面的代码演示了使用方法。

// extend usage
var a = { val: 1 },
b = { val: 2 }; ko.utils.extend(a, b);
console.log(a.val); // console: 2 // unwrapObservable usage
var c = ko.observable(99), d = 98;
console.log(ko.utils.unwrapObservable(c)); // console: 99
console.log(ko.utils.unwrapObservable(d)); // console: 98 // array "map" utility function usage
var arr = [100, 101];
var mapped = ko.utils.arrayMap(arr, function (item) {
return item + 50;
}) console.log(arr); // console: [ 150, 151 ]

Data-bind statements

我们一直关注 Knockout 的脚本库,实际上,Knockout 被设计为可以简单地将 JavaScript 对象绑定到 HTML 中。API 使用与 HTML5 兼容的 data-bind 语法。在我们前面的示例中,你可以看到可以简单地将 HTML 元素的属性绑定到 ViewModel 的属性上。data-bind 语法允许使用逗号分隔的绑定定义,下面的示例演示了使用方式。

<span data-bind="text: myText"></span>
<div data-bind="visible: isVisible, with: someProp"></div>
<input data-bind="value: someVal,
css: {
'error': !someVal.isValid(),
'success': someVal.isValid()
}"/>

Applying bindings

applyBindings 是 Knockout 一切工作启动的起点。大多数的示例都演示了将一个 ViewModel 作为参数的使用方式。但是你可以通过第二个参数来指定一个 DOM 对象,Knockout 将只会绑定到这个 DOM 节点及其子节点上。

多数的应用只有一个 ViewModel ,在调用 applyBinding 的时候,也仅仅传递一个 ViewModel 参数。但是,我创建过许多复杂的应用程序,在一个页面中使用了多个 ViewModel 对象,使用多个 ViewModel 的分别处理提示,设置,还有当前用户的信息等等。在这些情况下,通过限制 Knockout 绑定的节点数量,可以获取性能的优势。如果你仅仅需要更新页面的部分内容,就不要通过 Knockout 绑定到整个页面上。

Binding handlers

我曾经提到过 Knockout 提供了许多的扩展点。有一些比 Knockout 的 Binding handler 更方便。虽然通过 data-bind 语法实现了 binding handler 。Knockout 还允许我们自定义绑定的处理器,所以,我们可以实现,或者重写,我们自定义的功能。

在 MVVM 风格的开发中, 我们会有两种类型的绑定:单向和双向绑定。单向的绑定是简单的信息读取,将 ViewModel 中的数据读取出来绑定到 DOM 中。你可以想像出双向的数据绑定就是在单向的基础之上,将 DOM 对象的更新返回到 ViewModel 的属性上。Knockout 允许我们创建所有类型的绑定,下面的代码演示了基本处理器使用。

ko.bindingHandlers['myHandler'] = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
}, update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { }
};

如你所见,我们提供了两个钩子来实现我们的逻辑。Init 和 update 函数。这些函数的参数如下所示:

  • element: 定义 data-bind 的元素
  • valueAccessor:返回 ViewModel 绑定属性值得函数。如果绑定到 Observable 属性,那么回返回这个 Observalbe,在我们的处理逻辑中,需要将这个 Observable 进行 upwarp处理。
  • allBindingAccessor:类似于 valueAccessor ,但是它返回一个包含所有绑定和绑定值的对象。
  • viewModel:传递给 applyBindings 的视图模型或者根对象
  • bindingContext:专用的一个特殊对象,包含表示当前绑定上下文环境的特定信息。绑定上下文中有一个 $data 属性表示当前的绑定,这个属性经常与 viewModel 是相同的。还有 $parent 属性和 $parents 属性,表示绑定元素的上级节点。通常在使用 with 的时候才会使用这些属性。

你可以在想,这些东西看起来都差不多,我们应该在哪里实现我们的业务逻辑呢?init 函数仅仅在调用 applyBinding 的时候调用一次。Knockout 遍历整个 DOM 树,查找 data-bind 语法,处理它们,在每个需要的绑定上,调用 init 方法。然后,在调用 init 方法之后,立即调用 update 方法,以后,在绑定发生变化的时候会多次调用这个方法 ( 如果是 Subscribable )。

我的处理方式是在 init 中注册我所有的事件处理器 ( change, blur, focus ) ,然后在 update 中处理 HTML。

下面的代码演示了常见的单向绑定,这个例子与 visible 正好相反,我们可以使用 isHidden 而不是 isVisible。

// invisible -> the inverse of 'visible'
ko.bindingHandlers['invisible'] = {
update: function (element, valueAccessor) {
var newValueAccessor = function () {
// just return the opposite of the visible flag!
return !ko.utils.unwrapObservable(valueAccessor());
}; return ko.bindingHandlers.visible.update(element, newValueAccessor); }
};

下面的代码演示了双向的绑定,这个例子演示对一个数字的验证,从元素中获取数据传递到 ViewModel,在 ViewModel 发生变化的时候也可以传递到 DOM。

// simple number parsing
function parseNumber(strVal){
return parseInt(strVal, 10);
} // very basic two-way binding handler
ko.bindingHandlers['number'] = {
init: function (element, valueAccessor, allBindingsAccessor) {
//handle the input changing
ko.utils.registerEventHandler(element, "change", function () {
var observable = valueAccessor();
var number = parseNumber(element.value);
if (number !== NaN) {
observable(element.value);
}
});
}, update: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
var number = parseNumber(value);
if (number !== NaN) {
element.setAttribute("value", number);
}
}
};

Summary

你可以看到 Knockout 是一个非常成熟的脚本库,在这一节我们学到下面的内容:

  • Knockout 的核心对象和使用方式
  • Knockout 的实用工具
  • 如何创建和管理多个的 ViewModel
  • 定制绑定处理器

翻译:Knockout 快速上手 - 5: 你需要知道的顶级特性 续的更多相关文章

  1. 翻译:Knockout 快速上手 - 4: 你需要知道的顶级特性

    Knockout 最棒的一个特点就是它的可扩展性.Knockout 存在大量的扩展点,包含大量的工具来创建我们的应用程序.许多开发者除了 Knockout 核心库之外没有使用任何其他的脚本库 ( 甚至 ...

  2. 翻译:Knockout 快速上手 - 3: knockoutJS 快速上手

    许多时候,学会一种技术的有效方式就是使用它解决实际中的问题.在这一节,我们将学习使用 Knockout 来创建一个常见的应用,库存管理应用. 应用概览 在创建我们的应用之前,我们需要一个公司,来理解应 ...

  3. 翻译:Knockout 快速上手 - 2: 安装 knockoutJS

    只需要五个简单的步骤,就可以做好使用 Knockout 开发的准备! 第一步 我们需要什么? 最低限度,为了完成后面的教程,你需要如下的准备 Web 浏览器 文本编辑器 你的电脑上大约 2M 的磁盘空 ...

  4. [翻译]lithium 快速上手(QuickStart)

      ​ 快速入门 经典博客教程 很感谢你尝试Li3!这一部分栏目为那些想了解这个框架可以做什么的php用户所设计.像这样深入代码是一种很好的方式去体会快速应用开发(Rapid Application ...

  5. knockoutJS 快速上手

    翻译:Knockout 快速上手 - 3: knockoutJS 快速上手 许多时候,学会一种技术的有效方式就是使用它解决实际中的问题.在这一节,我们将学习使用 Knockout 来创建一个常见的应用 ...

  6. 快速上手RaphaelJS-Instant RaphaelJS Starter翻译(一)

       (目前发现一些文章被盗用的情况,我们将在每篇文章前面添加原文地址,本文源地址:http://www.cnblogs.com/idealer3d/p/Instant_RaphaelJS_Start ...

  7. EF Core 快速上手——EF Core 入门

    EF Core 快速上手--EF Core 介绍 本章导航 从本书你能学到什么 对EF6.x 程序员的一些话 EF Core 概述 1.3.1 ORM框架的缺点 第一个EF Core应用   本文是对 ...

  8. Flask入门和快速上手

    目录 Flask入门和快速上手 python三大主流框架对比 Flask安装 依赖 可选依赖 创建flask项目 flask最小应用--hello word 非法导入名称 调试模式 路由 唯一的 UR ...

  9. 第2章 初学 emWin 的准备工作及其快速上手

    以下内容转载自安富莱电子论坛:http://forum.armfly.com/forum.php?mod=viewthread&tid=24552&extra=page%3D3%26f ...

随机推荐

  1. 纠结的NTP安装过程

    为了部署实验用的openstack环境,其中有NTP的安装环节.在这个过程中,真是折腾了一下午...遇到了一些问题! 由于公司内部网络管理的原因,很多网站没有办法访问,比如公开的时间服务站点,我找了几 ...

  2. MVC4 WebAPI(二)——Web API工作方式

    http://www.cnblogs.com/wk1234/archive/2012/05/07/2486872.html 在上篇文章中和大家一起学习了建立基本的WebAPI应用,立刻就有人想到了一些 ...

  3. java ScriptEngine 使用 (支持JavaScript脚本,eval()函数等)

    Java SE 6最引人注目的新功能之一就是内嵌了脚本支持.在默认情况下,Java SE 6只支持JavaScript,但这并不以为着Java SE 6只能支持JavaScript.在Java SE ...

  4. PYTHON对文件及文件夹的一些操作

    python中对文件.文件夹的操作需要涉及到os模块和shutil模块. 创建文件:1) os.mknod("test.txt") 创建空文件2) open("test. ...

  5. 反转(开关问题) POJ 3276

    POJ 3276 题意:n头牛站成线,有朝前有朝后的的,然后每次可以选择大小为k的区间里的牛全部转向,会有一个最小操作m次使得它们全部面朝前方.问:求最小操作m,再此基础上求k. 题解:1.5000头 ...

  6. Hibernate中get和load的区别

    get获取的对象立即执行sql查询数据库中当前实体表中的数据,如果外键关联的其他实体表如果配置了懒加载关闭,则也会查询出外键关联的其他实体表中的数据,否则外键关联的其他实体表则以代理对象表示(称其为代 ...

  7. POJ-3461 Oulipo(KMP,模式串在主串中出现次数)

    题意:给你两个字符串p和s,求出p在s中出现的次数. 显然,我们要先把模式串放到前面,之后主串放后面,中间隔开,这样就可以根据前缀数组的性质来求了. 我先想直接把p接到s前面,之后求Next数组对st ...

  8. hdu 5437 Alisha’s Party 模拟 优先队列

    Problem Description Princess Alisha invites her friends to come to her birthday party. Each of her f ...

  9. POJ 1986 DIstance Query LCA水题

    给出一棵树,对于每一个询问,给出2个节点,输出2个节点的距离. 输入中有字母,那个是没有用的,不用管. 思路: 0.选择编号为1的节点作为树的root (注意:有些题的边是单向的,这时候我们要根据节点 ...

  10. bug_ _java.lang.IllegalArgumentException: View not attached to window manager

    ============= 1   view not attached to window manager 转自:http://hi.baidu.com/spare_h/blog/item/7fa3e ...