Knockout.js — это легковесный JavaScript-фреймворк, реализующий паттерн MVVM (Model-View-ViewModel), который позволяет связывать данные модели с пользовательским интерфейсом и автоматически обновлять отображение при изменении состояния. Основной механизм — обсерваблы (observables), которые представляют собой специальные объекты, отслеживающие изменения значений.
var viewModel = {
firstName: ko.observable("Иван"),
lastName: ko.observable("Петров")
};
ko.applyBindings(viewModel);
В примере firstName и lastName являются
наблюдаемыми. Любое изменение их значений автоматически обновит элементы
DOM, к которым они привязаны через data-bind.
Привязка данных осуществляется с помощью атрибута
data-bind:
<p data-bind="text: firstName"></p>
<input data-bind="value: firstName" />
Изменение текста в <input> сразу отразится в
<p> благодаря двухсторонней привязке.
var items = ko.observableArray(["яблоко", "банан"]);
items.push("груша");
Любое обновление массива автоматически изменит элементы DOM, если они
привязаны через foreach:
<ul data-bind="foreach: items">
<li data-bind="text: $data"></li>
</ul>
Computed observables — это свойства, значения которых вычисляются на основе других обсерваблов. Они автоматически обновляются при изменении зависимостей.
var viewModel = {
firstName: ko.observable("Иван"),
lastName: ko.observable("Петров"),
fullName: ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this)
};
Использование в шаблоне:
<p data-bind="text: fullName"></p>
Knockout.js позволяет связывать функции с событиями DOM через
event и click:
var viewModel = {
counter: ko.observable(0),
increment: function() {
this.counter(this.counter() + 1);
}
};
<button data-bind="click: increment">Увеличить</button>
<p data-bind="text: counter"></p>
Шаблоны позволяют повторно использовать куски HTML и динамически отображать элементы:
<script type="text/html" id="item-template">
<div>
<span data-bind="text: name"></span> - <span data-bind="text: price"></span>
</div>
</script>
<div data-bind="template: { name: 'item-template', foreach: products }"></div>
var viewModel = {
products: ko.observableArray([
{ name: "Книга", price: 300 },
{ name: "Ручка", price: 50 }
])
};
ko.applyBindings(viewModel);
Knockout.js поддерживает создание пользовательских привязок для расширения функциональности. Привязки можно использовать для интеграции с другими библиотеками или создания нестандартного поведения:
ko.bindingHandlers.fadeVisible = {
init: function(element, valueAccessor) {
var value = valueAccessor();
$(element).toggle(ko.unwrap(value));
},
update: function(element, valueAccessor) {
var value = valueAccessor();
ko.unwrap(value) ? $(element).fadeIn() : $(element).fadeOut();
}
};
<div data-bind="fadeVisible: isVisible">Скрываемый блок</div>
Knockout.js легко интегрируется с AJAX и Promises. Обсерваблы можно использовать для хранения загруженных данных и автоматического обновления интерфейса:
var viewModel = {
users: ko.observableArray([])
};
fetch("/api/users")
.then(response => response.json())
.then(data => viewModel.users(data));
ko.applyBindings(viewModel);
<ul data-bind="foreach: users">
<li data-bind="text: name"></li>
</ul>
Knockout.js имеет официальное расширение Knockout Context Debugger, которое добавляет панель в инструменты разработчика Chrome или Firefox. Основные возможности:
Расширение интегрируется через кнопку в панели элементов, показывая дерево привязок и все связанные модели. Это особенно полезно при работе со сложными и динамическими интерфейсами.
Дополнительно доступны сторонние расширения, предоставляющие:
Использование этих инструментов значительно ускоряет отладку и помогает визуализировать реактивные связи между моделью и представлением.
Knockout.js эффективно работает с большим количеством привязок, однако при сложных вычислениях рекомендуется использовать:
deferred updates для отложенного обновления
computed-свойств.dispose() для временных
computed-свойств.Это предотвращает избыточные перерасчеты и сохраняет производительность интерфейса даже при сложных динамических данных.
Knockout.js совместим с модульными системами, такими как RequireJS или ES6-модули. Это позволяет структурировать код, разделяя модель, представление и логику, а также интегрировать Knockout с другими библиотеками и фреймворками без конфликтов.
import ko from 'knockout';
export class ProductViewModel {
constructor(name, price) {
this.name = ko.observable(name);
this.price = ko.observable(price);
}
}
Использование модульного подхода упрощает масштабирование и поддержку крупных приложений, сохраняя реактивные свойства интерфейса.