Webix. Первое знакомство с JavaScript фреймворком
Эта статья предназначена для тех, кто хочет узнать об основах использования этого фреймворка. В ней я постараюсь подробно рассказать о том, как начать работу с Webix. Также стоит обратить внимание на то, какие дополнительные полезные инструменты, помимо библиотеки, предлагают разработчики.
В качестве примера я создал вот такую заготовку для онлайн плеера, что соответствует, на мой взгляд, духу времени, поскольку буквально всё нынче стремится утечь в онлайн, будь то хранение данных в облаках или потоковое аудио и видео.
Исходный код можно писать по мере прочтения статьи, а можно сразу скачать с гитхаба и разбираться с ним в процессе.
В двух словахWebix — это JavaScript фреймворк, с помощью которого можно создавать десктопные и мобильные веб-приложения с отзывчивым дизайном. Фреймворк доступен под двумя лицензиями: GNU GPLv3 и коммерческой.Особенности:
— Легкость освоения. Документация довольно подробна, и понять, как все устроено, несложно. Для того, чтобы начать работу, не нужно быть JS-гуру или JS-ниндзя. Не нужно даже понимать, в чем разница между ними.— Интеграция с популярными фреймворками. Реализована интеграция с Backbone.js, AngularJS и jQuery. Последняя фича, например, позволяет создавать Webix-виджеты с использованием jQuery-синтаксиса.— Интеграция со сторонними виджетами. В этом пункте ограничимся списком: Mercury, Nicedit, Tinymce, CodeMirror, CKEditor, Raphael, D3, Sigma, JustGage, Google Maps, Nokia Maps, Yandex Maps, dhtmlxScheduler and dhtmlxGantt.— Размер — маленький, скорость — большая. В сжатом виде .js-файл весит всего 128 КБ, и при этом все работает довольно-таки быстро (по словам разработчиков так и вовсе «летает»).— Поддержка тачскрина. Созданные виджеты одинаково хорошо себя чувствуют как на десктопах, так и на смартфонах/планшетах.
От слов к делу От списка особенностей, которые, думаю, мало кто читает от начала до конца, перейдем к практике. Но сначала предлагаю снова посетить главную страницу библиотеки и обратить внимание на интерактивную демку. Она состоит всего из десяти (10!) строк кода. Результат выглядит довольно симпатично. Если открыть эту демку в отдельном окне (вот ссылка на нее в онлайн-редакторе, если не хотите возиться) и поэкспериментировать с его размерами, можно убедиться в том, что виджет отображается корректно вне зависимости от предлагаемых обстоятельств. Может закрасться подозрение, что такое поведение не дается даром и нужно изрядно повозиться с таблицей стилей. Что ж, вот и проверим. Начать следует, как и положено, с начала.Скачать и распаковать. Впрочем, можно обойтись и без этого Для того чтобы начать использовать библиотеку, нужно сперва получить необходимые файлы. Для этого нужно отправиться на страницу загрузки. Выбираем понравившуюся версию (готов поспорить, в 99 случаях из 100 ей окажется Standard) — и получаем заветный zip-файл. Внутри можно обнаружить файлы `license.txt`, `readme.txt` и `whatsnew.txt`, которые могут показаться любопытными для тех, кто любит изучать все досконально. Помимо этого, интересным может оказаться содержимое папки `samples`, в которой можно посмотреть примеры того, что полезного с помощью Webix можно смастерить.Но больше всего на данный момент нас интересует содержимое папки `codebase`, а именно два файла, которые понадобятся для работы: `webix.js` и `webix.css`. Для того, чтобы можно было использовать Webix, нужно включить эти файлы в HTML-файл будущего проекта:
Впрочем, архив с библиотекой можно даже не скачивать. Все необходимые файлы доступны через CDN. Чтобы использовать эту возможность, можно подключить эти файлы следующим образом:
Но лучше все же скачать библиотеку целиком. Помимо сэмплов, в архиве также можно найти набор скинов. Использовать их проще простого, и позже я покажу, как это можно сделать.
Инициализация Теперь можно перейти непосредственно к работе с Webix.Вся Webix-магия происходит внутри конструктора webix.ui (). Если нужно удостовериться в том, что код начнет выполняться после того, как страница полностью загрузится, следует поместить его в webix.ready (function (){}). Выглядеть все это должно так:
webix.ready (function (){ webix.ui ({ /*код приложения*/ }); }); Лэйауты Прежде чем перейти непосредственно к приложению, нужно разобраться, как можно создавать лэйауты. Наш будущий плеер будет состоять из следующих основных частей: дерево каталогов, в котором будут отображаться все доступные альбомы; обложка альбома; плейлист в виде таблицы и панель управления.Для того, чтобы наполнить страницу содержимым нужно добавить описание необходимого элемента в формате JSON. Итак, приступим.
При создании лэйаута используются атрибуты rows и cols, с помощью которых можно создавать строки и столбцы соответственно. Вот пример создания простого лэйаута, состоящего из двух строк:
webix.ui ({ rows: [ { template: «Row One»}, { template: «Row Two»} ] }); Вот как будет выглядеть результат:
В этом примере с помощью template: «Row One» был создан простой контейнер, в который можно поместить любой HTML-контент.
Можно создавать вложенные контейнеры:
webix.ui ({ rows: [ { template: «Row One»}, { cols:[ { template: «Column One»}, { template: «Column Two»} ]} ] }); Результат:
Комбинируя вложенные строки и столбцы, можно добиться необходимого результата. По-умолчанию контейнеры заполняют все доступное пространство и, создавая четыре контейнера, мы получим четыре одинаковых прямоугольных области. Для того, чтобы задать нужные размеры элементов, можно использовать знакомые всем по CSS свойства width и height.
Таким образом, код для лэйаута нашего будущего плеера будет выглядеть вот так:
webix.ui ({ rows: [ {type: «header», template: «Online Audio Player»}, {cols: [ {rows: [ {template: «Tree»}, {view: «resizer»}, {template: «Album Art», width: 250, height: 250} ]}, {view: «resizer»}, {rows: [ {template: «Playlist»}, {template: «Controls», height: 60} ]} ] } ] }); Помимо уже знакомых колонок и столбцов, я также добавил кое-что новое. type: «header» превращает элемент в заголовок. Также были добавлены несколько элементов resizer, которые, как и следует из названия, нужны для изменения размеров контейнера. Ресайзер, как и все прочие UI-компоненты, создаeтся с помощью свойства view, которое позволяет создавать списки, кнопки, формы и т.д.
Вот как выглядит макет будущего приложения на данном этапе:
Теперь у нас есть области нужных размеров и возможность изменить эти размеры на свой вкус.
Страница размечена, настало время вдохнуть жизнь в элементы нашего приложения.
Посадить дерево… Знакомимся с Tree Widget
Начнем с дерева каталогов. Поскольку создание полнофункционального плеера выходит за рамки данной статьи (а также из нежелания столкнуться с возможными проблемами с копирайтом), вместо реальных файлов я использовал простые текстовые данные, которые будут помещены в файл data.js, который будет заполняться содержимым по мере необходимости. Сперва нужно добавить в него информацию об исполнителях и альбомах:
recordsData = [
{id:»1», value: «Oceansize», data: [
{id:»1.1», value: «Everyone Into Position»},
]},
{id:»2», value: «Little People», data: [
{id:»2.1», value: «Mickey Mouse Operation»},
]},
];
Двух исполнителей с одним альбомом для каждого из них будет достаточно, чтобы понять базовый принцип. Теперь нужно заставить дерево работать. Во-первых, необходимо подключить файл данных к HTML-фалу. Для этого нужно добавить следующий код между тегами
Во-вторых, вместо template: «Tree» в фигурные скобки нужно вставить код, который создаст дерево:
view: «tree», data: «recordsData», select: true Эта строка создает дерево на основе данных из массива recordsData из файла данных. select: true дает возможность выбирать один из элементов дерева, отключенную по-умолчанию.
Вот как это выглядит на данный момент:
Выуживаем информацию. Использование таблиц для отображения данных Теперь давайте посмотрим, как работают таблицы данных. Для того, чтобы проверить их работу, нужно добавить в файл data.js два новых массива. gridColumns содержит названия столбцов, которые будут отображаться в нашем списке, а oceanData содержит информацию о треках для первого альбома первого исполнителя: название и продолжительность каждой песни. gridColumns = [ { dataIndex: «title», header: «Title» }, { dataIndex: «duration», header: «Duration» } ];
oceanData = [ {id:»1», title:»01. The Charm Offensive», duration:»7:19»}, {id:»2», title:»02. Heaven Alive», duration:»6:20»}, {id:»3», title:»03. A Homage to Shame», duration:»5:52»}, {id:»4», title:»04. Meredith», duration:»5:26»}, {id:»5», title:»05. Music for a Nurse», duration:»8:16»}, {id:»6», title:»06. New Pin», duration:»5:11»}, {id:»7», title:»07. No Tomorrow», duration:»7:10»}, {id:»8», title:»08. Mine Host», duration:»4:10»}, {id:»9», title:»09. You Can«t Keep a Bad Man Down», duration:»7:36»}, {id:»10», title:»10. Ornament. The Last Wrongs», duration:»9:21»} ]; Для того, чтобы отобразить эти данные в виде сортируемой таблицы, нужно заменить template: «Playlist» на:
view: «datatable», autoConfig: true, data: oceanData Работает этот код так: view: «datatable» создает таблицу данных, autoConfig: true помогает сконфигурировать таблицу и создать столбцы на основе данных из массива gridColumns. В качестве расходного материала для таблицы используется массив oceanData.
Вот как выглядит приложение с таблицей:
Прошу заметить, что данные в таблице можно сортировать, но названиям или по длительности песни.
Все бы хорошо, да только вот дерево и плейлист работают отдельно друг от друга. Неплохо было бы научить их взаимодействовать.
Операция «Кооперация». Заставляем дерево и список работать сообща Для этого понадобится проделать некоторую подготовительную работу. Я постараюсь ее минимизировать, чтобы поскорее насладиться результатом.Во-первых, недурно бы изменить формат данных в файле data.js. Нужно изменить id для альбомов, а также добавить информацию для альбома второго исполнителя, чтобы было из чего выбирать. Она не отличается от таковой для предыдущего, поэтому мы приведем только часть массива peopleData:
recordsData = [ {id:»1», value: «Oceansize», data: [ {id: «oceanData», value: «Everyone Into Position»}, ]}, {id:»2», value: «Little People», data: [ {id: «peopleData», value: «Mickey Mouse Operation»}, ]}, ];
peopleData = [ {id:»1», title:»01. Basique», duration:»3:38»}, {id:»2», title:»02. Moon», duration:»3:47»}, <......> ]; Значение id для альбомов из массива recordsData совпадает с именем массива информации для соответствующего альбома. Это важно, потому что так будет быстрее.
Теперь вернемся к коду приложения. Сначала нужно создать переменную, в которой будет храниться значение элемента, выбранного в дереве. По-умолчанию она будет содержать значение первого альбома в списке. Затем нужно изменить код для построения дерева и таблицы, чтобы они смогли взаимодействовать друг с другом и реагировать на события:
var selected = oceanData; webix.ui ({ /*…*/ {view: «tree», id: «myTree», data: «recordsData», select: oceanData, on: { onSelectChange: function (){ selected = $$(«myTree»).getSelectedId (); if (isNaN (selected)) { $$(«myList»).clearAll (); $$(«myList»).define («data», selected); $$(«myList»).refresh (); } } } }, /*…*/ {view: «datatable», id: «myList», autoConfig: true, data: selected} Итак, что мы здесь имеем? Переменная selected по-умолчанию хранит значение первого альбома из дерева, данные которого и отображаются в таблице сразу после загрузки приложения. В код дерева и таблицы были добавлены атрибуты id со значениями myTree и myList соответственно. Они нужны для того, чтобы получить доступ к содержимому этих элементов. Свойство `select: oceanData` определяет `id` элемента списка, выбранного по-умолчанию. Далее используется обработчик событий. Код
on: { onSelectChange: function (){ } выполняется в тот момент, когда пользователь выбирает новый элемент в дереве. Когда это происходит, выполняется код, помещенный в тело функции. В нашем случае происходит следующее: строка selected = $$(«myTree»).getSelectedId (); присваивает переменной id выбранного в данный момент элемента дерева. Для папки это будет цифра, соответствующая ее номеру в иерархии, а для альбома — имя массива, содержащего информацию о нем. Поскольку выводить на экран информацию о папке в наши планы не входит, сперва нужно проверить, не является ли возвращенное значение цифрой: if (isNaN (selected)). Если это не цифра (а нам только этого и нужно), то список обновляется с помощью этого кода:
$$(«myList»).clearAll (); $$(«myList»).define («data», selected); $$(«myList»).refresh (); Сначала список очищается, затем инициализируется измененным значением selected с помощью метода define (), который принимает два значения: свойство, которое нужно изменить, и новое значение для этого свойства. Затем содержимое таблицы обновляется.
И, собственно, результат:
Теперь можно переключаться между разными элементами дерева и данные в таблице при этом будут обновляться.
Полученные знания о взаимодействии элементов понадобятся на следующем этапе, на котором будет добавлена возможность просматривать обложки альбомов.
Для визионеров Ну что ж, придется попотеть еще немного, чтобы увидеть обложки. Для этого понадобится новая переменная, которая будет содержать путь к обложке по-умолчанию: var coverPath = «imgs/oceanData.jpg»; Поскольку в этом случае, как и в предыдущем, вид приложения меняется в соответствии с изменениями в дереве, код необходимый для смены обложек также нужно добавлять в код дерева. Сразу после $$(«myList»).refresh (); добавим такие строки:
coverPath = «imgs/» + selected + ».jpg» $$(«myCover»).define («data», {src: coverPath}); Названия файлов обложек совпадают со значениями id соответствующих альбомов, а значит, можно снова использовать значение переменной selected по аналогии с предыдущим шагом. Затем нужно изменить состояние контейнера `myCover`, в котором отображается обложка. Для этого был использован уже знакомый метод define ().
Осталось заставить соответствующий контейнер отображать картинку. Для этого строку template: «Album Art», width: 250, height: 250 нужно заменить на:
width: 250, height: 250, id: «myCover», data: {src: coverPath}, template: function (obj) { return '' } Этот пример не так очевиден на первый взгляд. Давайте разбираться. width и height были установлены заранее, ничего нового тут нет; id нужен для доступа к содержимому контейнера — тоже без сюрпризов;, а вот дальше начинается самое интересное: свойство data определяет содержимое контейнера. Значение src соответствует пути к файлу изображения, и именно его нужно изменить, чтобы изменилась обложку. Последующая функция нужна для генерации HTML-кода, и ее без лишней нужды лучше не трогать.
Теперь проверим, как работает отображение обложек. Внешний вид по-умолчанию:
Внешний вид после выбора нового элемента дерева:
Обложки меняются, как и задумано. Осталось добавить кнопки управления.
Берем приложение под контроль Самая ответственная часть нашего примера. Добавление кнопок. Поскольку наш плеер минималистичен донельзя, обойтись можно тремя кнопками: Previous, Play / Pause и Next.Поскольку некоторый опыт работы с Webix уже имеется, этот последний штрих не будет таким уж сложным. Для добавления кнопок нужно заменить template: «Controls», height: 60 на:
cols: [ {view: «button», value:»< Previous"}, {view:"button", value:"Play / Pause"}, {view:"button", value:"Next >»}] Здесь создаются три столбца, в каждый из которых добавляется по кнопочке.
Вот результат:
Итоги Ну что тут можно сказать. Самое сложное — создание интерфейса с некоторой интерактивностью — позади. Пустяки, вроде возможности воспроизведения файлов, каждый сможет реализовать сам. Для того, чтобы создать отзывчивый (responsive) интерфейс, мне не пришлось возиться с css-кодом. Разработчики уже повозились с ним за меня, а мне осталось только использовать свойства `width` и `height`, чтобы придать элементам нужный размер.На этом, пожалуй, всё… Или…? Ах, да! Чуть не забыл о скинах. Прикрутить их к готовому проекту несложно, поэтому много времени это не займет.
Рестайлинг на лету В каталоге skins можно обнаружить вот такой вот список доступных вариантов: aircompact.css clouds.css glamour.css metro.css touch.css air.css compact.css flat.css light.css terrace.css web.css Для того, чтобы попробовать тот, который показался наиболее заманчивым, нужно просто подключить соответствующую таблицу стилей к HTML-файлу. Например, добавив
можно изменить вид приложения на такой:
Проверить работу приложения самому можно здесь. Если хотите поэкспериментировать, добавить новых исполнителей или новые столбцы для плейлиста, исходный код доступен на GitHub.
Ну, а на этом, пожалуй, действительно все. Надеюсь, статья помогла вам освоить основы работы с Webix. Продолжить погружение вам поможет доступная и подробная документация с множеством примеров.
Адьо!