[Разработка веб-сайтов, JavaScript, Программирование, HTML] Фреймворк Webix Jet глазами новичка. Часть 1. Композиция и навигация

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
20-Мар-2021 17:31


В предыдущих статьях из цикла JavaScript библиотека Webix глазами новичка вы узнали как создать приложение на основе компонентов Webix UI. В этой публикации я хочу подробно рассмотреть создание аналогичного приложения с использованием архитектуры и возможностей фреймворка Webix Jet, а также какие преимущества это дает. Статья будет полезна как для тех кто уже знаком с Webix UI, так и для новичков, ведь код библиотеки интуитивно понятен и удобен в использовании.Обзор Webix Jet Webix — это библиотека UI компонентов. Для создания полноценного приложения на основе Webix UI вам не обязательно использовать дополнительные инструменты. Однако по мере расширения и увеличения количества кода могут возникнуть трудности с его организацией. Команда Webix позаботилась о решении этой проблемы и разработала собственный фреймворк для построения архитектуры приложения. Фреймворк Webix Jet позволяет создавать очень гибкое и хорошо управляемое одностраничное приложение, используя паттерн Model-View. При таком подходе, логика работы с данными и отображение элементов интерфейса четко разделяются. Каждый компонент разрабатывается и тестируется отдельно от других. Также имеются готовые решения многих задач, которые реализуются через API, плагины и конфигурации.Архитектура Jet-приложения основана на модулях view компонентов. Каждый компонент являет собой независимую часть интерфейса. Вы можете комбинировать модули, использовать повторно в разных частях приложения и управлять их отображением с помощью URL. Подробнее о работе с Webix-jet вы узнаете на примере создания собственного SPA.Построение собственного Webix Jet приложения Процесс создания приложения мы рассмотрим в следующем порядке:
  • Интерфейс приложения
  • Структура приложения
  • Создание и конфигурация приложения
  • View модули интерфейса
  • Модели работы с данными
  • Локализация приложения
В документациях Webix UI и Webix Jet можно ознакомиться с использованными в статье компонентами и API фреймворка.С кодом готового приложения можно ознакомиться тут. Интерфейс приложения Начнем с описания интерфейса нашего приложения и разделения его на смысловые части. Сделать это крайне важно, так как каждую обособленную часть мы будем разрабатывать и хранить в отдельном модуле.Интерфейс разделяем на 3 части:
  • Тулбар 
  • Сайдбар
  • Панель сменяемых модулей

Тулбар находится в верхней части экрана. Он содержит лейбл с названием приложения в левой части и кнопки переключения локализации в правой.Сайдбар находится в левой части экрана и содержит меню для навигации между сменяемыми модулями интерфейса. Панель сменяемых модулей составляет основу приложения и расположена в центральной части экрана. Здесь вы сможете видеть 3 автономных модуля, которые содержат определенную часть интерфейса приложения. Они будут сменять друг друга по клику на опции меню. Структура приложения У нашего приложения будет следующая структура:
  • файл index.html является стартовой страницей и единственным html файлом  
  • файл sources/myapp.js содержит необходимые конфигурации приложения
  • папка sources/views состоит из следующих файлов:
    • top.js содержит главный модуль, который объединяет все элементы интерфейса
    • toolbar.js содержит модуль с описанием тулбара
    • form.js содержит модуль с описанием формы
    • films.js содержит сменяемый модуль
    • users.js содержит сменяемый модуль
    • products.js содержит сменяемый модуль
  • папка sources/models содержит модули для операций с данными
  • папка sources/styles содержит CSS файлы
  • папка sources/locales содержит модули локализации.
Такая организация кода помогает разделять разные аспекты разработки на отдельные составляющие и эффективно управлять ими. Это особенно актуально при работаете с большим количеством кода.Мы будем создавать интерфейс приложения комбинируя несколько subview модулей в файле top.js. Subview - это модули интерфейса, которые входят в состав других view. Они могут быть статическими и динамическими. Давайте подробнее их рассмотрим.Статические subview импортируются при помощи команды import и включаются в интерфейс компонента напрямую. Например, мы будем использовать статический модуль toolbar.js в главном модуле top.js. Для понимания принципа работы динамических subview важно упомянуть о такой сущности Jet, как URL. Он позволяет формировать иерархию отображения view модулей и осуществлять навигацию между ними. URL отображается в адресной строке браузера после имени домена и спецсимвола `/#!/`.Например, с помощью URL мы можем указать модуль, который будет отображаться первым: http://localhost:8080/#!/top - приложение отобразит интерфейс файла top.jshttp://localhost:8080/#!/top/films - приложение отобразит интерфейс файла top.js и films.js (если в top.js указан плейсхолдер для films.js).Мы реализуем 3 динамических subview модуля, каждый из которых будет отображаться при соответствующем значении URL: Навигация между динамическими subview реализуется при помощи изменения URL. Например, если нам надо отобразить модуль users на панели сменяемых модулей, мы можем изменить текущий URL на http://localhost:8080/#!/top/users и увидим интерфейс файла top.js и users.js. Переключение между опциями меню работает по такому же принципу.Навигация с помощью URL удобна и тем, что браузер хранит историю посещения разных url-адресов, и при клике на кнопку “Назад” в  браузере, мы можем перейти к предыдущему модулю. Также URL хранит состояние приложения. Если пользователь переключится на вкладку Users при помощи меню и обновит страницу, то приложение отобразит тот модуль, URL которого был установлен в адресной строке браузера до перезагрузки.Если такое отображение URL неудобно, вы можете либо убрать спец. символы из URL, либо вовсе не показывать его в адресной строке - на работу приложения это не повлияет.Подробнее о настройках URL можно узнать тут.Подробнее ознакомиться с тонкостями использования subview вы можете тут.Создание и конфигурирование приложения Итак, мы разобрали интерфейс и структуру файлов нашего демо приложения. Сейчас пришло время непосредственно заняться его созданием. Для начала важно правильно настроить нужные конфигурации и подключить необходимые инструменты.В файле sources/myapp.js находится модуль конфигурации приложения. Он расширяется базовым классом JetApp, который содержит все необходимые инструменты управления.Импортируем и подключаем стили css и базовый класс JetApp.
import "./styles/app.css";
import { JetApp } from "webix-jet";
Создаем класс MyApp нашего приложения и наследуем его от базового JetApp. В конструкторе класса прописываем необходимые настройки.Для активации режима отладки нужно установить параметр debug:true. Теперь фреймворк будет отображать все ошибки, которые могут возникнуть в процессе разработки модулей. Преимущество работы с Jet состоит в том, что сбои в работе отдельных модулей не будут влиять на работоспособность всего приложения, но без debug:true вы о них не узнаете.  Для определения стартовой страницы нужно установить параметр start и указать значение URL для начальной загрузки: start:"/top/films". Теперь при первоначальной загрузке приложения мы увидим главный модуль top.js и сменяемый модуль films.js.
export default class MyApp extends JetApp{
  constructor(config){
    const defaults = {
      //активируем режим отладки, для отображения ошибок
      debug:true,
      //устанавливаем стартовый URL загрузки приложения
      start:"/top/films"
    };
     super({ ...defaults, ...config });
  }
}
После создания класса и внесения необходимых конфигураций, нам нужно его инициализировать.
const app = new MyApp();
Далее отображаем приложение через метод render() и оборачиваем его в webix.ready(), чтобы HTML страница успела загрузиться до начала выполнения кода.
webix.ready(() => app.render());
Мы создали и настроили наше приложение. Теперь самое время перейти к непосредственной разработке view модулей интерфейса. View модули интерфейса Мы будем создавать view компоненты как классы ES6 и наследовать их от базового JetView. Такой подход позволяет расширить модуль встроенными Jet методами и получить доступ к управлению жизненным циклом компонента.В начале каждого модуля необходимо подключить базовый JetView класс, который хранит конфигурации и инструменты для управления логикой view модулей. В собственных классах мы используем методы config() и init(), которые наследуются от JetView, а также можем создавать собственные методы для хранения кастомной логики.Элементы интерфейса описываем и возвращаем через метод config().Работу с данными осуществляем через метод init().Модуль TopView (top.js) Давайте создадим главный модуль TopView в файле top.js, который будет включать сайдбар, футер, тулбар и динамические subview модули. В адресной строке он будет отображаться как #!/top/ .Тулбар мы создадим в другом модуле и импортируем сюда. Он будет включаться как статический subview.Импортируем базовый класс JetView и модуль ToolbarView.
import { JetView } from "webix-jet";
import ToolbarView from "views/toolbar";
Создаем и наследуем класс TopView от базового JetView. В методе config() описываем основные элементы интерфейса и возвращаем комбинированный view.
export default class TopView extends JetView{
  config(){
     //здесь будет описан интерфейс
  }
}
Обратите внимание, что созданный класс необходимо экспортировать при помощи команды export default, чтобы Webix Jet включил его в приложение.Внутри метода config() мы описываем сайдбар, который содержит меню с опциями для переключения динамических модулей интерфейса. Для этого используем компонент List библиотеки Webix UI. В свойстве data указываем названия опций меню и их id, которые будут использоваться для формирования URL.
const sidebar = {
  view:"list",
  data:[
    { value:"Dashboard", id:"films" },
    { value:"Users", id:"users" },
    { value:"Products", id:"products" }
  ]
};
Описываем футер, который содержит информацию копирайта и находится в самом низу экрана. Мы не выделяем его в отдельный модуль, так как это незначительный элемент. Для этого используем компонент Template.
const footer = {
  template:"The software is provided by <a href='https://webix.com'> webix.com </a>. All rights reserved ©"
};
Теперь нужно объединить все компоненты и сформировать структуру интерфейса приложения. Помимо собственных компонентов сайдбар и футер, мы включаем статический ToolbarView и динамические subview.
config(){
  const ui = {
    rows:[
      ToolbarView, //включаем как статический subview модуль
      {
        cols:[
          sidebar,
          { view:"resizer" },
          { $subview:true } //включаем динамические subview
        ]
      },
      footer
    ]
  };
  return ui;
}
Возвращаем комбинированный view ui,  который включает в себя все элементы интерфейса.Теперь нужно настроить панель сменяемых модулей (плейсхолдер { $subview:true } ). При выборе той или иной опции меню, наше приложение будет задавать необходимый сегмент URL (films, users, products) и отображать одноименный модуль на месте плейсхолдера {$subview:true}. Обязательное условие, чтобы id опций меню и названия файлов, хранящих модули интерфейса, совпадали. Для того чтобы установить необходимый URL, воспользуемся встроенным методом JetView this.show(id). В качестве аргумента передаем id соответствующей опции меню. Этот id задает URL относительно того модуля, в котором вызван метод show(). В нашем случае метод изменит значение URL после #!/top/ и установит туда переданный в аргументе id.  Таким образом, полный URL будет #!/top/{id}.Например, при клике на опцию Users, виджет вызовет this.show("users") и установит URL  #!/top/users. На месте { $subview:true } отобразится модуль файла views/users.js .Модуль ToolbarView (toolbar.js) Определяем модуль ToolbarView в файле toolbar.js, который  включается как статический subview в главном модуле файла top.js. Создаем и наследуем класс ToolbarView от базового JetView. В методе config() описываем необходимые компоненты и возвращаем их.Описываем тулбар, который содержит лейбл с названием приложения и кнопки переключения локализации. Для этого используем такие компоненты Webix UI как Toolbar, Label и Segmented.
export default class TopView extends JetView{
  config(){
    const toolbar = {
      view:"toolbar",
      elements:[
        { view:"label", label:"Demo App" },
        {
          view:"segmented",
          options:[
            { id:"en", value:"En" },
            { id:"ru", value:"Ru" }
          ]
        }
      ]
    };
    return toolbar;
  }
}
Теперь пришло время перейти к созданию динамических subview, которые будут сменяться в зависимости от сегмента URL, следующего после #!/top/. У нас будет 3 сменяемых модуля:
  • FilmsView
  • UsersView
  • ProductsView.
Каждый модуль мы будем разрабатывать в отдельном файле.Модуль FilmsView (films.js) Интерфейс модуля состоит из таблицы фильмов и формы для их редактирования. Таблица состоит из 5 столбцов, в которых мы реализуем сортировку и фильтрацию данных. Форму создадим в отдельном модуле и будем включать ее как статический subview.Определяем модуль FilmsView в файле films.js, который будет включаться как динамический subview в файле top.js. Модуль будет отображаться при значении URL: #!/top/films.В начале кода импортируем модуль FormView из файла form.js, который содержит форму для редактирования фильмов и будет включаться как статический subview.
import FormView from "views/form";
Создаем и наследуем класс FilmsView от базового JetView. В методе config() описываем основные элементы интерфейса и возвращаем комбинированный view.Описываем таблицу фильмов с помощью компонента Datatable. Через свойство columns конфигурируем столбцы. У каждого столбца должен быть уникальный id. Сортировка данных столбца реализуется при помощи свойства sort. Для столбцов с текстовыми значениями мы используем sort:"text", а для числовых sort:"int". Чтобы добавить фильтр в хедер столбца, мы используем конфигурацию {content:"textFilter"} для текстовых значений и {content:"selectFilter"} для числовых.
const film_table = {
  view:"datatable",
  columns:[
    { id:"id", header:""},
    { id:"title", header:["Film title", { content:"textFilter" }], fillspace:true, sort:"text" },
    { id:"year", header:["Released", { content:"selectFilter" }], sort:"int" },
    { id:"votes", header:"Votes", sort:"int" },
    { id:"rating", header:"Rating", sort:"int" }
  ]
};
Формируем интерфейс модуля. Включаем собственный компонент film_table с таблицей фильмов и статический модуль FormView, который хранит интерфейс формы для редактирования фильмов.
return {
  cols:[
    film_table,
    FormView //включаем как статический subview модуль
  ]
};
Модуль FormView (form.js) Интерфейс модуля содержит форму для редактирования фильмов. Форма состоит из 4 полей ввода, а также кнопок “Сохранить” и “Очистить”. Определяем модуль FormView в файле form.js. Создаем и наследуем класс FormView от базового JetView. В методе config() описываем основные элементы интерфейса и возвращаем комбинированный view.Описываем форму для редактирования фильмов с помощью компонента Form. Через свойство elements конфигурируем поля ввода и кнопки для управления формой.
config(){
  const film_form = {
    view:"form",
    elements:[
      { type:"section", template:"edit films" },
      { view:"text", name:"title", label:"Title" },
      { view:"text", name:"year", label:"Year" },
      { view:"text", name:"rating", label:"Rating" },
      { view:"text", name:"votes", label:"Votes" },
      {
        cols:[
          { view:"button", value:"Save", css:"webix_primary" },
          { view:"button", value:"Clear", css:"webix_secondary" }
        ]
      },
      {}
    ]
  };
  return film_form;
}
Модуль UsersView (users.js) Интерфейс модуля состоит из тулбара, списка пользователей и диаграммы пользователей. В тулбаре находится строка поиска, кнопка для добавления новых пользователей, а также 2 кнопки для сортировки списка пользователей по возрастанию и убыванию. Список пользователей содержит имя, возраст и страну. Диаграмма отображает возраст пользователей. Определяем модуль UsersView в файле users.js, который будет включаться как динамический subview в файле top.js. Модуль будет отображаться при значении URL: #!/top/users.Создаем и наследуем класс UsersView от базового JetView. В методе config() описываем элементы интерфейса при помощи компонентов List, Toolbar и Chart.  Описываем список пользователей при помощи компонента List. Через свойство template конфигурируем шаблон списка, который будет включать имя, возраст и страну.
const list = {
  view:"list",
  template:"#name#, #age#, #country#"
};
Описываем тулбар для работы со списком при помощи компонента Toolbar . Через свойство elements конфигурируем строку поиска и кнопки для управления списком пользователей.
const list_toolbar = {
  view:"toolbar",
  elements:[
    //кнопка добавления нового пользователя
    { view:"button", value:"Add new person", css:"webix_primary" },
    //строка поиска
    { view:"search" },
    //кнопки сортировки
    { view:"button", value:"Sort asc" },
    { view:"button", value:"Sort desc" }
  ]
};
Описываем диаграмму пользователей при помощи компонента Chart. Задаем тип диаграммы type:"bar", значения для столбцов value:"#age#".  Конфигурируем оси при помощи свойств xAxis и yAxis.
const chart = {
  view:"chart",
  type:"bar",
  value:"#age#",
  xAxis:{
    template:"#name#",
    title:"Age"
  },
  yAxis:{
    start:0,
    end:100,
    step:10
  }
};
Формируем интерфейс модуля. Комбинируем и возвращаем компоненты list_toolbar, list и chart.
return { rows:[list_toolbar, list, chart] };
Модуль ProductsView (products.js) Интерфейс модуля состоит из древовидной таблицы, которая содержит элементы высшего и вложенного уровней. Определяем модуль ProductsView в файле products.js, который будет включаться как динамический subview в файле top.js. Модуль будет отображаться при значении URL: #!/top/products.Создаем и наследуем класс ProductsView от базового JetView. В методе config() описываем древовидную таблицу при помощи компонента Treetable. Через свойство columns конфигурируем столбцы таблицы. Используем конфигурацию template:"{common.treetable()} #title#",  чтобы задать вложенные элементы.
config(){
  const products_treetable = {
    view:"treetable"
    columns:[
      { id:"id", header:"" },
      { id:"title", header:"Title", fillspace:true,  template:"{common.treetable()} #title#" },
      { id:"price", header:"Price" }
    ]
  };
  return products_treetable;
}
Мы описали интерфейс нашего приложения. Теперь пришла очередь рассказать о том,  как осуществляется работа с данными. Модели работы с данными Давайте разбираться с тем, как работать с моделями данных. В принципе, подключать данные не обязательно, и можно загружать их сразу в компоненты минуя модели. Но для серьезного приложения такие сущности как view и model лучше разделять.Логика работы с моделями данных хранится в файлах директории sources/models. Предполагается, что мы взаимодействуем с сервером и загружаем данные асинхронно. Для этого используем метод webix.ajax(). Функция webix.ajax() делает асинхронный запрос по указанному в аргументе адресу и возвращает промис-объект. В случае успешной загрузки мы получим объект, значения которого будем загружать в необходимые нам модули.Данные нам нужны для 3 сменяемых subview
  • FilmsView
  • UsersView
  • ProductsView.
Для каждого модуля создаем отдельную модель, как на примере ниже.
// models/films.js
export function getData(){
  return webix.ajax("../../data/film_data.js");
}
Все 3 модели будут отличаться только аргументом запроса, в котором мы указываем путь к данным на сервере. В нашем случае данные хранятся в папке ../../data/.Теперь для каждого view модуля необходимо импортировать метод getData из соответствующей модели.
import { getData } from "models/films";  // для FilmsView
import { getData } from "models/users";  //для UsersView
import { getData } from "models/products";  //для ProductsView.
Далее мы должны передать данные из модели в необходимый компонент. Интерфейс модуля описывается внутри метода config() и становится доступным после инициализации. Внутри специального метода init() класса JetView, мы можем получить доступ к нужному data-компоненту (List, Datatable, Chart) и загрузить в него данные при помощи метода parse().
config(){
...
  return {
    cols:[
      film_table,
      FormView
    ]
  };
}
init(view){
  const datatable = view.queryView("datatable");
  datatable.parse(getData());
}
В метод init() приходит параметр view, который ссылается на объект, возвращенный методом config() того же модуля. Это может быть layout с таблицей и другими компонентами. Внутри layout мы ищем таблицу по названию компонента (view.queryView("datatable");), а затем загружаем в нее данные.Чтобы передать данные из промис-объекта который возвращает нам метод getData(), нужно вызвать метод parse() для Webix компонента и передать туда промис в качестве аргумента. Когда данные будут загружены, компонент их обработает и отобразит в интерфейсе приложения.Локализация приложения Инструментарий фреймворка Webix Jet позволяет с легкостью реализовать локализацию приложения. Для этого мы будем использовать встроенный сервис Locale. Этот сервис нужно подключить в файле sources/myapp.js, т.к. он будет использоваться глобально для всего приложения. Для этого мы импортируем модуль plugins, который содержит встроенные сервисы, вместе с базовым JetApp.
import { JetApp, plugins } from "webix-jet";
После создания и инициализации класса MyApp, мы подключаем сервис plugins.Locale. Сделать это необходимо до вызова метода render().
const app = new MyApp();
app.use(plugins.Locale);
webix.ready(() => app.render());
Сервис Locale устанавливает связь с файлами локализации, которые находятся в директории sources/locales. Файлы en.js и ru.js хранят объекты с элементами локализации.
// locales/en.js
export default {
  Dashboard : "Dashboard",
  Users : "Users",
  ...
}
// locales/ru.js
export default {
  Dashboard : "Панель",
  Users : "Пользователи",
  ...
}
Далее, в каждом отдельном view модуле мы получаем метод из сервиса локализации.
const _ = this.app.getService("locale")._;
Этот метод мы будем вызывать каждый раз, когда нам надо перевести какое-либо текстовое выражение. В качестве аргумента нужно передавать ключи, по которым будут подтягиваться значения из объекта файла установленной локали: _("some text"). При смене локализации, Jet перерисует приложение с учетом значений установленной локали. Почти готово, осталось только рассказать о том, каким образом пользователь сможет переключать языки в нашем приложении. Как вы помните, в тулбаре мы создали кнопку Segmented со значениями En и Ru. Теперь нам нужно создать обработчик, который будет вызываться при клике на соответствующую кнопку и применять нужную локализацию.
config(){
...
  {
    view:"segmented",
    options:[
      { id:"en", value:"En" },
      { id:"ru", value:"Ru" }
    ],
    click:() => this.toggleLanguage()
  }
...
}
toggleLanguage(){
  const langs = this.app.getService("locale");
  const value = this.getRoot().queryView("segmented").getValue();
  langs.setLang(value);
}
Для этого мы создаем функцию-обработчик toggleLanguage() как метод класса ToolbarView. Здесь же находится сегментная кнопка, при клике на которую мы будем вызывать наш обработчик.Внутри функции получаем доступ к сервису локализации, считываем значение заданной опции (значение берется из id  - "en" или "ru") и устанавливаем выбранную локаль с помощью метода  setLang().При описании функции используем метод this.getRoot(). С его помощью мы получаем доступ к view, возвращенный нам методом config() - здесь это Toolbar. Внутри view мы ищем компонент с именем segmented, чтобы получить объект кнопки и считать ее значение.Вот такими простыми манипуляциями в Webix Jet  реализуется смена локализации.Заключение С помощью фреймворка Webix Jet мы создали структурированное одностраничное приложение. Интерфейс разделен на модули view, которые хранятся в отдельной директории sources/views. Логика работы с данными отделена от компонентов интерфейса и хранится в директории sources/models. Реализована локализация приложения за счет использования плагина Locale базового класса JetApp. Сейчас это мини-приложение, но с такой архитектурой его легко масштабировать и поддерживать.С кодом готового приложения можно ознакомиться тут.Webix Jet имеет достаточно широкий спектр инструментов и конфигураций, которые значительно упрощают процесс разработки приложения на основе компонентов Webix UI. Более детально мы рассмотрим их в следующих статьях посвященных Webix Jet.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_razrabotka_vebsajtov (Разработка веб-сайтов), #_javascript, #_programmirovanie (Программирование), #_html, #_webixjet, #_framework, #_webix, #_javascript, #_application, #_razrabotka_vebsajtov (
Разработка веб-сайтов
)
, #_javascript, #_programmirovanie (
Программирование
)
, #_html
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 08:25
Часовой пояс: UTC + 5