В Knockout.js компоненты служат строительными блоками интерфейса, позволяя создавать повторно используемые и изолированные элементы. Основной принцип композиции заключается в том, что один компонент может включать в себя другие компоненты, обеспечивая модульность и упрощая поддержку кода.
Регистрация компонента выполняется через
ko.components.register, где указывается имя компонента и
его конфигурация, включающая шаблон и модель представления:
ko.components.register('user-card', {
viewModel: function(params) {
this.name = ko.observable(params.name);
this.age = ko.observable(params.age);
},
template: `
<div class="user-card">
<h2 data-bind="text: name"></h2>
<p>Возраст: <span data-bind="text: age"></span></p>
</div>
`
});
Вложенные компоненты позволяют создавать иерархию элементов.
Например, компонент user-list может включать несколько
экземпляров user-card:
ko.components.register('user-list', {
viewModel: function(params) {
this.users = ko.observableArray(params.users || []);
},
template: `
<div class="user-list">
<!-- ko foreach: users -->
<user-card params="name: name, age: age"></user-card>
<!-- /ko -->
</div>
`
});
В этом примере user-list получает массив пользователей и
отображает для каждого отдельный user-card. Связь данных
происходит через params, что позволяет передавать значения
из родительского компонента в дочерний.
Передаваемые параметры могут быть observable или простыми значениями. Knockout.js автоматически отслеживает изменения observable, что делает интерфейс динамичным. Пример использования observable:
var viewModel = {
users: ko.observableArray([
{ name: ko.observable('Иван'), age: ko.observable(30) },
{ name: ko.observable('Мария'), age: ko.observable(25) }
])
};
ko.applyBindings({ usersList: viewModel.users });
При изменении значения name или age
соответствующие дочерние компоненты обновятся автоматически.
Иногда требуется взаимодействие с дочерними компонентами после их
рендеринга. Knockout.js предоставляет контекст
компонента через $component, $parent,
$root и $data. Пример обращения к
родительскому observable из дочернего компонента:
<user-card params="name: $parent.name, age: $parent.age"></user-card>
Это позволяет дочернему компоненту использовать данные родителя и реагировать на изменения без прямого вмешательства в его модель.
Компоненты можно загружать асинхронно, что особенно полезно для больших приложений. Knockout поддерживает asynchronous component loading:
ko.components.register('async-widget', function(callback) {
require(['widgets/async-widget'], function(module) {
callback(module);
});
});
Таким образом, основной код не блокируется, а компоненты подгружаются по мере необходимости.
Knockout позволяет динамически изменять вложенные компоненты через динамические binding handlers. Пример использования:
<div data-bind="component: { name: currentComponent, params: componentParams }"></div>
currentComponent может изменяться в runtime, что
позволяет заменять один компонент на другой без перезагрузки страницы,
сохраняя реактивность данных.
Компоненты часто обмениваются информацией через custom
events или callback-функции, передаваемые в
params:
ko.components.register('child-button', {
viewModel: function(params) {
this.clickHandler = function() {
if (params.onClick) params.onClick('Данные от дочернего компонента');
};
},
template: `<button data-bind="click: clickHandler">Нажать</button>`
});
Родительский компонент может передавать функцию-обработчик, обеспечивая гибкую связь между уровнями композиции.
Шаблоны компонентов могут быть внешними или встроенными. Использование внешних файлов повышает масштабируемость:
ko.components.register('external-template', {
viewModel: function(params) { /* логика */ },
template: { require: 'text!templates/external-template.html' }
});
Это позволяет создавать библиотеку компонентов и легко использовать их в различных частях приложения.
Композируемые и вложенные компоненты в Knockout.js обеспечивают чистую архитектуру, реактивность данных и повторное использование интерфейсных элементов. Использование параметров, контекстов, асинхронной загрузки и динамической замены компонентов создаёт мощный инструмент для построения сложных, масштабируемых приложений на JavaScript.