KnockoutJS - вычисляемые наблюдаемые
Computed Observable - это функция, которая зависит от одного или нескольких Observable и автоматически обновляется при изменении лежащих в основе Observable (зависимостей).
Вычисляемые наблюдаемые можно связывать в цепочку.
Синтаксис
this.varName = ko.computed(function(){
...
... // function code
...
},this);
пример
Давайте посмотрим на следующий пример, который демонстрирует использование Computed Observables.
<!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 каждый ввод, принимаемый из пользовательского интерфейса, по умолчанию имеет формат String. Поэтому их нужно преобразовать в числа, чтобы выполнять с ними арифметические операции.
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);
В следующей строке вычисленное среднее значение отображается в пользовательском интерфейсе. Обратите внимание, что тип привязки данных totalAvg - это просто текст.
<p>Average := <span data-bind = "text: totalAvg"></span></p>
Вывод
Давайте выполним следующие шаги, чтобы увидеть, как работает приведенный выше код -
Сохраните приведенный выше код в computed-observable.htm файл.
Откройте этот HTML-файл в браузере.
Введите любые 2 числа в текстовые поля и убедитесь, что вычисляется среднее значение.
Управление этим
Обратите внимание, что в приведенном выше примере второй параметр предоставляется как thisк вычисляемой функции. Невозможно сослаться на Observablesa() и b() без предоставления this.
Чтобы преодолеть это, self используется переменная, которая содержит ссылку на this. При этом нет необходимости отслеживать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;
});
}
Чистые вычисленные наблюдаемые
Вычисляемый наблюдаемый должен быть объявлен как PureComputed Observable, если этот Observable просто вычисляет и возвращает значение, а не напрямую изменяет другие объекты или состояние. Pure Computed Observables помогает Knockout эффективно управлять переоценкой и использованием памяти.
Явное уведомление подписчиков
Когда Computed Observable возвращает значение примитивного типа данных (String, Boolean, Null и Number), его подписчики уведомляются тогда и только тогда, когда происходит изменение фактического значения. Это означает, что если Observable получил то же значение, что и предыдущее значение, то его подписчики не уведомляются.
Вы можете сделать так, чтобы Computed Observables всегда явно уведомляла наблюдателей, даже если новое значение совпадает со старым, используя notify синтаксис следующий.
myViewModel.property = ko.pureComputed(function() {
return ...; // code logic goes here
}).extend({ notify: 'always' });
Ограничение уведомлений об изменениях
Слишком много дорогих обновлений может привести к проблемам с производительностью. Вы можете ограничить количество уведомлений, получаемых от Observable, используяrateLimit атрибут следующим образом.
// make sure there are updates no more than once per 100-millisecond period
myViewModel.property.extend({ rateLimit: 100 });
Определение того, является ли свойство вычисляемым наблюдаемым
В определенных ситуациях может потребоваться выяснить, является ли свойство вычисляемым наблюдаемым. Следующие функции могут использоваться для определения типов наблюдаемых.
Sr.No. | Функция |
---|---|
1 | ko.isComputed Возврат true если свойство Computed Observable. |
2 | ko.isObservable Возврат true если свойство - Observable, Observable array или Computed Observable. |
3 | ko.isWritableObservable Возврат trueif Observable, Observable array или Writable Computed Observable. (Это также называется ko.isWriteableObservable) |
Записываемые вычисляемые наблюдаемые
Computed Observable является производным от одного или нескольких других Observable, поэтому он доступен только для чтения. Однако возможно, что можно сделать Computed Observable доступным для записи. Для этого вам необходимо предоставить функцию обратного вызова, которая работает с записанными значениями.
Эти доступные для записи Computed Observables работают так же, как и обычные Observables. Кроме того, они требуют создания настраиваемой логики для вмешательства в действия чтения и записи.
Можно присвоить значения многим свойствам 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 - это свойство pureComputed, принимаемое из пользовательского интерфейса. yourAge Наблюдаемое происходит от rawDate.
Даты в JavaScript обрабатываются в миллисекундах. Следовательно, обе даты (сегодняшняя дата и дата рождения) конвертируются в миллисекунды, а затем разница между ними конвертируется обратно в годы и месяцы.
Вывод
Давайте выполним следующие шаги, чтобы увидеть, как работает приведенный выше код -
Сохраните приведенный выше код в writable_computed_observable.htm файл.
Откройте этот HTML-файл в браузере.
Введите любую дату рождения и наблюдайте, что возраст рассчитывается.