Графический пользовательский интерфейс (GUI) это сложный слой системы, состоящий из множества компонентов, называемых виджетами, которые отвечают за представление бизнес-модели приложения пользователю и обрабатывают логику взаимодействия с ним через это представление. В этом цикле статей мы выделим основные элементы виджета и варианты их компоновки.
Популярные JS-фреймворки используют концепцию виджетов компоную реализацию различных элементов. Как правило применяется MVC структура, позволяющая легко реализовывать и расширять библиотеку виджетов. При этом виджет состоит из следующих элементов:
- Модель - описывает данные бизнес-модели приложения в пригодном для представления виде
- Представление - описывает логику рендеринга (преобразования) модели в визуальный компонент интерфейса
- Контроллер - описывает логику взаимодействия пользователя с виджетом и реакции последнего на них
Все три перечисленных элемента мы коротко рассмотрим далее, а более подробно в следующих статьях цикла.
Модель
Модель виджета чаще всего представляется в виде набора данных (массива, словаря или объекта), которыми оперирует виджет. Часто модель выделяется в отдельный класс с собственными методами, инкапсулируя не только данные, но и логику получения их от сервера.
Рассмотрим простой пример приложения, работающего с данными клиентов:
<?php
class Client{
private $name;
}
class Product{
private $name;
}
class OrderRow{
private $product;
private $count;
}
class Order{
private $client;
private $rows;
}
Это бизнес-модель приложения, описывающая клиентов и продукты, доступные системы, а так же заказы конкретных клиентов. Класс Order
в данной модели выступает в качестве списка объектов OrderRow
, каждый из которых описывает количество заказанных продуктов.
При передаче экземпляров этой модели в слой представления, ее необходимо представить в доступном для виджета виде (преобразовать PHP в JS), именно здесь и применяется модель представления, которая может быть описана с помощью следующих классов:
function Client(name){
this.name = name;
}
function Product(name){
this.name = name;
}
function OrderRow(product, count){
this.product = product;
this.count = count;
}
function Order(client){
this.client = client;
this.rows = [];
}
Order.prototype.addRow = function(row){
this.rows.push(row);
};
Данные классы могут быть расширены методами, облегчающими работу с ними для слоя представления.
Представление
Элементом, преобразующим модель виджета в конкретные графические элементы интерфейса (на пример в HTML), обычно выступает специальный класс или функция, содержащая логику этого преобразования. Для описанного выше примера может использоваться два рендера:
function OrderRowRender(row){
this.row = row;
}
OrderRowRender.prototype.render = function(){
return '<li>' + this.row.product.name + ' | ' + this.row.product.count + '</li>';
};
function OrderRender(order){
this.order = order;
}
Order.prototype.render = function(){
var result = '<ul>';
for(var i in this.order.rows){
var rowRender = new OrderRowRender(this.order.rows[i]);
result += rowRender.render();
}
result += '</ul>';
};
Здесь рендер OrderRowRender
служит для представления одной строки заказа в виде элемента li
, а OrderRender
отвечает за представления всего заказа и использует OrderRowRender
в качестве вспомогательного в цикле для представления каждой строки заказа. В результате может быть получен следующий код:
<ul>
<li>Гвозди | 10</li>
<li>Молоток | 2</li>
<li>Заклепки | 10</li>
</ul>
Контроллер
Контроллер виджета отвечает за обработку событий взаимодействия пользователя с представлением и изменение модели на основании этих взаимодействий. В нашем примере контроллер может быть встроен в класс виджета:
function OrderWidget(order, el){
this.order = order;
this.el = el;
}
OrderWidget.prototype.bind = function(){
$(this.el).on('click', 'li', this.onSelectRow);
};
// Метод контроллера, обрабатывающий событие выбора строки продукта пользователем.
OrderWidget.prototype.onSelectRow = function(e){
$(e.target).toggleClass('selected');
};
OrderWidget.prototype.render = function(){
var render = new OrderRender(this.order);
el.html(render.render());
this.bind();
};
В данном примере метод bind
служит для добавления обработчиков событий сформированного представления, а метод onSelectRow
обрабатывает эти события.
Послесловие
В данной статье мы галопом пробежались по понятию виджета и его элементам. Возможно статья оставила вам больше вопросов, нежели ответов, но не спешите, в следующих частях цикла мы подробно рассмотрим каждый элемент и приведем примеры их реализаций, потому все встанет на свои места.