- KnockoutJS Tutorial
- KnockoutJS - Home
- KnockoutJS - Overview
- KnockoutJS - Environment Setup
- KnockoutJS - Application
- KnockoutJS - MVVM Framework
- KnockoutJS - Observables
- Computed Observables
- KnockoutJS - Declarative Bindings
- KnockoutJS - Dependency Tracking
- KnockoutJS - Templating
- KnockoutJS - Components
- KnockoutJS Resources
- KnockoutJS - Quick Guide
- KnockoutJS - Resources
- KnockoutJS - Discussion
KnockoutJS - 计算可观察量
计算的 Observable 是一种依赖于一个或多个 Observable 的函数,并且每当其底层 Observable(依赖项)发生变化时就会自动更新。
计算的可观察量可以链接起来。
句法
this.varName = ko.computed(function(){
...
... // function code
...
},this);
例子
让我们看一下下面的示例,它演示了计算可观察量的用法。
<!DOCTYPE html>
<head >
<title>KnockoutJS Computed Observables</title>
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js"></script>
</head>
<body>
<p>Enter first number: <input data-bind = "value: a" /></p>
<p>Enter second number: <input data-bind = "value: b"/></p>
<p>Average := <span data-bind="text: totalAvg"></span></p>
<script>
function MyViewModel() {
this.a = ko.observable(10);
this.b = ko.observable(40);
this.totalAvg = ko.computed(function() {
if(typeof(this.a()) !== "number" || typeof(this.b()) !== "number") {
this.a(Number(this.a())); //convert string to Number
this.b(Number(this.b())); //convert string to Number
}
total = (this.a() + this.b())/2 ;
return total;
},this);
}
ko.applyBindings(new MyViewModel());
</script>
</body>
</html>
在下面的行中,前两行用于接受输入值。第三行打印这两个数字的平均值。
<p>Enter first number: <input data-bind = "value: a" /></p> <p>Enter second number: <input data-bind = "value: b"/></p> <p>Average := <span data-bind = "text: totalAvg"></span></p>
在下面几行中,Observables a和b的类型在 ViewModel 中首次初始化时为数字。然而,在 KO 中,从 UI 接受的每个输入默认都是字符串格式。所以需要将它们转换为Number,以便对它们进行算术运算。
this.totalAvg = ko.computed(function() {
if(typeof(this.a()) !== "number" || typeof(this.b()) !== "number") {
this.a(Number(this.a())); //convert string to Number
this.b(Number(this.b())); //convert string to Number
}
total = (this.a() + this.b())/2 ;
return total;
},this);
在下面的行中,计算出的平均值显示在 UI 中。请注意,totalAvg 的数据绑定类型只是文本。
<p>Average := <span data-bind = "text: totalAvg"></span></p>
输出
让我们执行以下步骤来看看上面的代码是如何工作的 -
将以上代码保存在compute-observable.htm文件中。
在浏览器中打开此 HTML 文件。
在文本框中输入任意 2 个数字,然后观察计算出平均值。
管理“这个”
请注意,在上面的示例中,第二个参数作为this提供给 Computed 函数。如果不提供this ,就不可能引用 Observables a()和b()。
为了克服这个问题,使用self变量来保存this的引用。这样做,就不需要在整个代码中跟踪这一点。相反,可以使用self 。
下面的 ViewModel 代码是使用 self 为上面的示例重写的。
function MyViewModel(){
self = this;
self.a = ko.observable(10);
self.b = ko.observable(40);
this.totalAvg = ko.computed(function() {
if(typeof(self.a()) !== "number" || typeof(self.b()) !== "number") {
self.a(Number(self.a())); //convert string to Number
self.b(Number(self.b())); //convert string to Number
}
total = (self.a() + self.b())/2 ;
return total;
});
}
纯计算可观测值
如果一个计算可观察对象只是计算并返回值而不直接修改其他对象或状态,那么该可观察对象应该被声明为纯计算可观察对象。Pure Computed Observables 帮助 Knockout 有效地管理重新评估和内存使用。
明确通知订阅者
当 Computed Observable 返回原始数据类型值(String、Boolean、Null 和 Number)时,当且仅当实际值发生更改时,它的订阅者才会收到通知。这意味着如果 Observable 收到的值与之前的值相同,那么它的订阅者不会收到通知。
通过使用如下的通知语法,您可以使计算的可观察量始终显式地通知观察者,即使新值与旧值相同。
myViewModel.property = ko.pureComputed(function() {
return ...; // code logic goes here
}).extend({ notify: 'always' });
限制变更通知
太多昂贵的更新可能会导致性能问题。您可以使用rateLimit属性限制从Observable 接收的通知数量,如下所示。
// make sure there are updates no more than once per 100-millisecond period
myViewModel.property.extend({ rateLimit: 100 });
查明某个属性是否计算可观察
在某些情况下,可能有必要查明某个属性是否是计算的可观察量。以下函数可用于识别 Observables 的类型。
| 先生。 | 功能 |
|---|---|
| 1 | ko.isCompated 如果该属性是计算可观察的,则返回true 。 |
| 2 | ko.isObservable 如果属性是 Observable、Observable 数组或 Computed Observable,则返回true 。 |
| 3 | ko.isWritableObservable 如果可观察、可观察数组或可写计算可观察则返回true 。(这也称为 ko.isWriteableObservable) |
可写的计算可观察量
计算的 Observable 派生自一个或多个其他 Observable,因此它是只读的。然而,有可能使 Computed Observable 变得可写。为此,您需要提供适用于写入值的回调函数。
这些可写的计算可观察量的工作方式就像常规可观察量一样。此外,它们还需要构建自定义逻辑来干扰读写操作。
我们可以使用链接语法为许多 Observables 或 Computed Observable 属性赋值,如下所示。
myViewModel.fullName('Tom Smith').age(45)
例子
以下示例演示了 Writable Computable Observable 的使用。
<!DOCTYPE html>
<head >
<title>KnockoutJS Writable Computed Observable</title>
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"></script>
</head>
<body>
<p>Enter your birth Date: <input type = "date" data-bind = "value: rawDate" ></p>
<p><span data-bind = "text: yourAge"></span></p>
<script>
function MyViewModel() {
this.yourAge = ko.observable();
today = new Date();
rawDate = ko.observable();
this.rawDate = ko.pureComputed ({
read: function() {
return this.yourAge;
},
write: function(value) {
var b = Date.parse(value); // convert birth date into milliseconds
var t = Date.parse(today); // convert todays date into milliseconds
diff = t - b; // take difference
var y = Math.floor(diff/31449600000); // difference is converted
// into years. 31449600000
//milliseconds form a year.
var m = Math.floor((diff % 31449600000)/604800000/4.3); // calculating
// months.
// 604800000
// milliseconds
// form a week.
this.yourAge("You are " + y + " year(s) " + m +" months old.");
},
owner: this
});
}
ko.applyBindings(new MyViewModel());
</script>
</body>
</html>
在上面的代码中,rawDate是从 UI 接受的 pureCompulated 属性。yourAge Observable 派生自rawDate。
JavaScript 中的日期以毫秒为单位进行操作。因此,两个日期(今天的日期和出生日期)都被转换为毫秒,然后它们之间的差异被转换回年和月。
输出
让我们执行以下步骤来看看上面的代码是如何工作的 -
将以上代码保存在writable_compulated_observable.htm文件中。
在浏览器中打开此 HTML 文件。
输入任何出生日期并观察计算出的年龄。