Model-View-ViewModel (MVVM) представляет собой архитектурный паттерн, который широко используется в разработке современных веб-приложений. Этот подход разделяет ответственность между тремя ключевыми компонентами:
Ember.js не следует строго этому паттерну, но его архитектура в значительной степени поддерживает идеи MVVM, что делает его подходящим фреймворком для реализации приложений с использованием этого паттерна.
Модели в Ember.js — это объекты, которые инкапсулируют данные и
бизнес-логику приложения. В Ember модели создаются с помощью класса
Ember.Object или, начиная с версии 3.5, с использованием
новой системы моделей через DS.Model из библиотеки Ember
Data. Эти модели отвечают за хранение данных, но не за их
отображение.
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
author: DS.attr('string'),
publishedAt: DS.attr('date')
});
В приведённом примере создаётся модель книги, которая содержит три
атрибута: title, author,
publishedAt. Это — базовые данные, которые могут быть
использованы в представлениях, но сами по себе они не содержат
информации о том, как эти данные должны быть показаны пользователю.
В Ember.js представления традиционно представляют собой шаблоны, написанные с использованием Handlebars. Эти шаблоны описывают, как должны быть отображены данные на странице. Важным моментом является то, что представление зависит от состояния модели или ViewModel. Ember использует двухстороннее связывание данных, что означает, что изменения в данных автоматически отражаются в представлении, и наоборот.
<h1>{{model.title}}</h1>
<p>{{model.author}}</p>
<p>Published on: {{model.publishedAt}}</p>
В шаблоне выше данные, связанные с моделью, отображаются в виде элементов HTML. Когда модель обновляется, представление также будет обновляться автоматически благодаря использованию Ember’s Bindings и Observers.
В Ember.js концепция ViewModel чаще всего реализуется с помощью контроллеров и компонентов. Контроллеры управляют состоянием представлений и преобразуют данные модели в формат, который удобно использовать в шаблонах. Компоненты, в свою очередь, представляют собой более модульные единицы, которые могут инкапсулировать как логику, так и представление.
Контроллеры в Ember.js — это объекты, которые управляют данными и состоянием для конкретных шаблонов. Контроллеры могут содержать свойства и методы, которые обеспечивают доступ к данным модели и управляют ими. Например:
import Controller from '@ember/controller';
export default Controller.extend({
actions: {
updateTitle(newTitle) {
this.set('model.title', newTitle);
}
}
});
В этом примере контроллер управляет моделью, предоставляя действие для обновления заголовка книги. Это действие можно вызвать из представления, что обеспечивает взаимодействие между представлением и моделью.
Компоненты в Ember.js — это более мощный инструмент для реализации паттерна MVVM. Компоненты могут содержать как данные (похожие на свойства ViewModel), так и шаблоны для отображения этих данных. Это позволяет создавать переиспользуемые и модульные блоки интерфейса. Например:
import Component from '@ember/component';
export default Component.extend({
title: 'Default Title',
author: 'Unknown Author'
});
<div>
<h1>{{title}}</h1>
<p>{{author}}</p>
</div>
В данном примере компонент хранит данные и отображает их с помощью шаблона. Это также является примером использования ViewModel, так как компонент управляет состоянием и предоставляет данные для отображения.
Ember.js автоматически поддерживает двустороннее связывание данных между моделью и представлением. Это означает, что любое изменение в модели автоматически обновляет представление, и наоборот, изменения в представлении могут быть переданы обратно в модель. Это свойство особенно важно для паттерна MVVM, поскольку оно позволяет создать отзывчивые и динамичные пользовательские интерфейсы.
Пример двустороннего связывания данных:
<input type="text" value={{model.title}} {{action "updateTitle" value="target.value"}} />
В этом примере значение поля ввода автоматически привязано к атрибуту
title модели. Когда пользователь вводит новый текст,
значение модели изменяется, что вызывает обновление в представлении.
Одной из ключевых характеристик Ember.js является система компонентов, которая активно используется для создания переиспользуемых элементов UI. Каждый компонент может иметь собственный ViewModel, отвечающий за бизнес-логику и отображение данных. Это позволяет создавать UI-элементы, которые могут быть использованы в разных частях приложения.
Пример компонента с независимой логикой и состоянием:
import Component from '@ember/component';
export default Component.extend({
tagName: 'button',
classNames: ['submit-button'],
click() {
this.sendAction('onSubmit');
}
});
В этом примере компонент представляет собой кнопку, которая вызывает
действие onSubmit при клике. Логика компонента изолирована
от других частей приложения, что делает его удобным для повторного
использования.
Реактивность — это способность фреймворка автоматически отслеживать изменения состояния и обновлять соответствующие части интерфейса. В Ember.js эта реактивность достигается через систему наблюдателей и геттеров, которая позволяет автоматически отслеживать изменения в свойствах объектов и обновлять представление, если необходимо.
import { computed } from '@ember/object';
export default Ember.Component.extend({
firstName: '',
lastName: '',
fullName: computed('firstName', 'lastName', function() {
return `${this.firstName} ${this.lastName}`;
})
});
В этом примере свойство fullName автоматически
вычисляется на основе значений firstName и
lastName. При изменении этих свойств fullName
будет пересчитано и обновлено, что является основой реактивности в
Ember.
Ember.js предоставляет мощные средства для реализации архитектурных паттернов, подобных MVVM. С помощью моделей, представлений, компонентов и контроллеров можно легко разделить ответственность за логику приложения и отображение данных. Двустороннее связывание и реактивность Ember делают этот фреймворк отличным выбором для создания сложных, динамичных и хорошо структурированных приложений.