Knockout observables提供了支持读取/写入值并在值改变时通知订阅者所需的基本功能。 但在某些情况下,您可能希望向可观察者添加其他功能。 这可能包括通过在可观察者前面放置一个可写的计算可观察符来向可观察或截取写入添加额外的属性。 敲除扩展器提供了一种简单和灵活的方式来对可观察者进行这种类型的扩充。

如何创建扩展器

创建扩展器涉及向ko.extenders对象添加一个函数。 函数接受observable本身作为第一个参数和第二个参数中的任何选项。 然后它可以返回observable或返回一些新的像一个计算的observable,它以某种方式使用原来的observable。

这个简单的logChange扩展器订阅了observable,并使用控制台写入任何更改以及可配置的消息。

ko.extenders.logChange = function(target, option) {
target.subscribe(function(newValue) {
console.log(option + ": " + newValue);
});
return target;
};

您将通过调用observable的extend函数并传递包含日志Change属性的对象来使用此扩展器。

this.firstName = ko.observable("Bob").extend({logChange: "first name"});

如果firstName observable值更改为Ted,那么控制台将显示名字:Ted。

示例1:强制输入为数字

此示例创建一个扩展器,该扩展器强制对可观察对象的写入被四舍五入到可配置的精度级别。 在这种情况下,扩展器将返回一个新的可写的计算可观察,它将位于真正的可观察的拦截写入之前。

(round to whole number)

(round to two decimals)

UI源码:

<p><input data-bind="value: myNumberOne" /> (round to whole number)</p>
<p><input data-bind="value: myNumberTwo" /> (round to two decimals)</p>

视图模型源码:

ko.extenders.numeric = function(target, precision) {
//create a writable computed observable to intercept writes to our observable
var result = ko.pureComputed({
read: target, //always return the original observables value
write: function(newValue) {
var current = target(),
roundingMultiplier = Math.pow(10, precision),
newValueAsNum = isNaN(newValue) ? 0 : +newValue,
valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier; //only write if it changed
if (valueToWrite !== current) {
target(valueToWrite);
} else {
//if the rounded value is the same, but a different value was written, force a notification for the current field
if (newValue !== current) {
target.notifySubscribers(valueToWrite);
}
}
}
}).extend({ notify: 'always' }); //initialize with current value to make sure it is rounded appropriately
result(target()); //return the new computed observable
return result;
}; function AppViewModel(one, two) {
this.myNumberOne = ko.observable(one).extend({ numeric: 0 });
this.myNumberTwo = ko.observable(two).extend({ numeric: 2 });
} ko.applyBindings(new AppViewModel(221.2234, 123.4525));

注意,为了自动从UI中删除被拒绝的值,有必要在计算的observable上使用.extend({notify:'always'})。 没有这个,用户可能输入一个无效的newValue,当四舍五入得到一个不变的valueToWrite。 然后,由于模型值不会改变,因此在UI中没有更新文本框的通知。 使用{notify:'always'}会导致文本框刷新(删除被拒绝的值),即使计算的属性没有更改值。

示例2:向可观察者添加验证

此示例创建一个扩展器,允许将observable标记为必需。 这个扩展器不是返回一个新的对象,而是简单地向现有的observable添加额外的子可观察量。 因为observables是函数,它们实际上可以有自己的属性。 但是,当视图模型转换为JSON时,子可观察项将被删除,我们将只剩下我们的实际observable的值。 这是一个很好的方法来添加只与UI相关的附加功能,而不需要发送回服务器。

UI源码:

<p data-bind="css: { error: firstName.hasError }">
<input data-bind='value: firstName, valueUpdate: "afterkeydown"' />
<span data-bind='visible: firstName.hasError, text: firstName.validationMessage'> </span>
</p>
<p data-bind="css: { error: lastName.hasError }">
<input data-bind='value: lastName, valueUpdate: "afterkeydown"' />
<span data-bind='visible: lastName.hasError, text: lastName.validationMessage'> </span>
</p>

视图模型晕吗:

ko.extenders.required = function(target, overrideMessage) {
//add some sub-observables to our observable
target.hasError = ko.observable();
target.validationMessage = ko.observable(); //define a function to do validation
function validate(newValue) {
target.hasError(newValue ? false : true);
target.validationMessage(newValue ? "" : overrideMessage || "This field is required");
} //initial validation
validate(target()); //validate whenever the value changes
target.subscribe(validate); //return the original observable
return target;
}; function AppViewModel(first, last) {
this.firstName = ko.observable(first).extend({ required: "Please enter a first name" });
this.lastName = ko.observable(last).extend({ required: "" });
} ko.applyBindings(new AppViewModel("Bob","Smith"));

应用多个扩展程序

多个扩展器可以在对可观察者的.extended方法的单个调用中应用。

this.firstName = ko.observable(first).extend({ required: "Please enter a first name", logChange: "first name" });

在这种情况下,required和logChange扩展器都会对我们的observable执行。

KnockoutJS 3.X API 第七章 其他技术(2) 使用扩展器来增加可观察量(监控属性)的更多相关文章

  1. KnockoutJS 3.X API 第七章 其他技术(4) 速率限制

    注意:这个速率限制API是在Knockout 3.1.0中添加的. 通常,更改的observable立即通知其订户,以便依赖于observable的任何计算的observable或绑定都会同步更新. ...

  2. KnockoutJS 3.X API 第七章 其他技术(8) 异步错误处理

    注意:本文档适用于Knockout 3.4.0及更高版本. ko.onError Knockout包装内部异步调用,并在抛出原始错误之前查找可选的ko.onError回调以执行(如果遇到异常). 这使 ...

  3. KnockoutJS 3.X API 第七章 其他技术(7) 微任务

    注意:本文档适用于Knockout 3.4.0及更高版本. Knockout的微任务队列 Knockout的微任务队列支持调度任务尽可能快地运行,同时仍然是异步的,努力安排它们在发生I / O,回流或 ...

  4. KnockoutJS 3.X API 第七章 其他技术(6) 使用“fn”添加自定义函数

    有时,您可能会通过向Knockout的核心值类型添加新功能来寻找机会来简化您的代码. 您可以在以下任何类型中定义自定义函数: 因为继承,如果你附加一个函数到ko.subscribable,它将可用于所 ...

  5. KnockoutJS 3.X API 第七章 其他技术(5) 使用其他事件处理程序

    在大多数情况下,数据绑定属性提供了一种干净和简洁的方式来绑定到视图模型. 然而,事件处理是一个常常会导致详细数据绑定属性的领域,因为匿名函数通常是传递参数的推荐技术. 例如: <a href=& ...

  6. KnockoutJS 3.X API 第七章 其他技术(3) 延迟更新

    .example { display: inline-block; padding: 1em; margin-right: 2em; background: #F6F6EF; } 注意:本文档适用于K ...

  7. KnockoutJS 3.X API 第七章 其他技术(1) 加载和保存JSON数据

    Knockout允许您实现复杂的客户端交互性,但几乎所有Web应用程序还需要与服务器交换数据,或至少将本地存储的数据序列化. 最方便的交换或存储数据的方式是JSON格式 - 大多数Ajax应用程序今天 ...

  8. KnockoutJS 3.X API 第六章 组件(3) 组件绑定

    组件绑定将指定的组件注入到元素中,并且可选地将参数传递给它. 本节目录 一个例子 API 组件生命周期 备注1:仅限模板组件 备注2:使用没有容器元素的组件 备注3:将标记传递给组件 处置和内存管理 ...

  9. KnockoutJS 3.X API 第三章 计算监控属性(1) 使用计算监控属性

    计算监控属性(Computed Observables) 如果你有一个监控属性firstName,和另一个lastName,你要显示的全名?可以使用计算监控属性来实现-它依赖于一个或多个其他监控属性, ...

随机推荐

  1. vs2012 发布web应用程序

    Visual Studio 2012 Visual Studio Express 2012 for Web 与 的Visual Studio 2010  Visual Studio Web发布更新 与 ...

  2. DFS序+线段树+bitset CF 620E New Year Tree(圣诞树)

    题目链接 题意: 一棵以1为根的树,树上每个节点有颜色标记(<=60),有两种操作: 1. 可以把某个节点的子树的节点(包括本身)都改成某种颜色 2. 查询某个节点的子树上(包括本身)有多少个不 ...

  3. DOM解析示例

    收藏信息.xml <?xml version="1.0" encoding="GB2312" standalone="no"?> ...

  4. 2-Sat问题

    二分+2-Sat 判断是否可行 输出字典序最小的解 输出字典序可行解 其实这些都是小问题,最重要的是建图,请看论文. 特殊的建边方式,如果a b是一对,a必须选,那么就是b->a建边. HDU ...

  5. sequelize常见操作使用方法

    关于sequelize的准备工作这里不再赘述. 一.引入sequelize模块 var Sequelize = require('sequelize'); 二.连接数据库 var sequelize  ...

  6. STM32之DMA+ADC

    借用小甲鱼的经典:各位互联网的广大网友们.大家早上中午晚上好..(打下小广告,因为小甲鱼的视频真的很不错).每次看小甲鱼的视频自学都是比较轻松愉快的..我在想,如果小甲鱼出STM32的视频,我会一集不 ...

  7. ubuntu环境下vmware取消自动启动服务

    概述其实vmware这个服务取不取消,影响不大,主要是我有强迫症,在不用虚拟机的时候,看着vmware占着进程真心不爽,想要解决这个问题,在用虚拟机的时候启动服务,反之,则停.接下来,我说一下实现吧. ...

  8. [ios]利用alertView 插入数据都数据库。笔记

    利用alertView 插入数据都数据库 -(void)addItemToList { UIAlertView *alter=[[UIAlertViewalloc]initWithTitle:@&qu ...

  9. Python之路Day15--CSS补充以及JavaScript(一)

    一.上节作业问题: 上节作业问题: 1.css重用 <style> 如果整个页面的宽度 > 900px时: { .c{ 共有 } .c1{ 独有 } } .c2{ 独有 } < ...

  10. spark - tasks is bigger than spark.driver.maxResultSize

    Error ERROR TaskSetManager: Total size of serialized results of 8113 tasks (1131.0 MB) is bigger tha ...