Статьи

Использование фабрики виджетов пользовательского интерфейса jQuery

Долгое время единственным способом написания пользовательских элементов управления в jQuery было расширение пространства имен $.fn . Это хорошо работает для простых виджетов, однако, как только вы начинаете создавать виджеты с большим состоянием, они быстро становятся громоздкими. Чтобы помочь в процессе создания виджетов, команда пользовательского интерфейса jQuery представила Фабрику виджетов, которая удаляет большую часть стандартного шаблона, который обычно связан с управлением виджетом.

Фабрика виджетов, являющаяся частью jQuery UI Core , предоставляет объектно-ориентированный способ управления жизненным циклом виджета. Эти жизненные циклы включают в себя:

  • Создание и уничтожение виджета
  • Изменение параметров виджета
  • Выполнение « супер » вызовов в подклассах виджетов
  • Уведомления о событиях

Давайте рассмотрим этот API, так как мы создадим простой виджет маркера.


Прежде чем мы создадим этот виджет, давайте разберемся с некоторыми строительными блоками виджета. Bullet Chart — это концепция, представленная Стивеном Фью как разновидность гистограммы.

Пуля Диаграмма

Диаграмма состоит из набора полос и маркеров, наложенных друг на друга, чтобы показать относительную производительность. Существует количественная шкала для отображения фактического диапазона значений. Располагая столбцы и маркеры таким образом, можно передавать больше информации без ущерба для читабельности. Легенда рассказывает, какую информацию мы собираем.

HTML-код для этой диаграммы выглядит так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!— Chart Container —>
<div class=»chart bullet-chart»>
 
  <!— Legend —>
  <div class=»legend» style=»»>
    <div class=»legend-item»>
      <span class=»legend-symbol marker green»>
      <span class=»legend-label»>Green Line
    </div>
  </div>
 
<!— Chart —>
  <div class=»chart-container» style=»width: 86%;»>
 
    <!— Quantitative Scale —>
    <div class=»tick-bar»>
      <div class=»tick» style=»left: 0%;»></div>
      <div class=»tick-label» style=»left: 0%;»>0</div>
      <div class=»tick» style=»left: 25%;»></div>
      <div class=»tick-label» style=»left: 25%;»>25</div>
      <div class=»tick» style=»left: 50%;»></div>
      <div class=»tick-label» style=»left: 50%;»>50</div>
      <div class=»tick» style=»left: 75%;»></div>
      <div class=»tick-label» style=»left: 75%;»>75</div>
      <div class=»tick» style=»left: 100%;»></div>
      <div class=»tick-label» style=»left: 100%;»>100</div>
    </div>
 
    <!— Bars —>
    <div class=»bar» style=»left: 0px; width: 75%;»
    <div class=»bar blue» style=»left: 0px; width: 50%;»
 
    <!— Markers —>
    <div class=»marker green» style=»left: 80%;»
    <div class=»marker red» style=»left: 50%;»
  </div>
</div>

Наш виджет, который мы назовем jquery.bulletchart , будет динамически генерировать этот HTML из предоставленных данных. Окончательный виджет можно посмотреть в исходных файлах, которые вы можете скачать с GitHub. Вызов для создания виджета должен выглядеть так:

Все значения в процентах. Опцию size можно использовать, когда вы хотите, чтобы несколько диаграмм располагались рядом друг с другом с относительным размером. Опция ticks используется для размещения меток на шкале. Маркеры и столбцы указываются в виде массива литералов объектов со свойствами title , value и css .


Теперь, когда мы знаем структуру виджета, давайте приступим к его созданию. Виджет создается путем вызова $.widget() с именем виджета и объекта, содержащего методы его экземпляра. Точный API выглядит так:

jQuery.widget(name[, base], prototype)

Сейчас мы будем работать только с аргументами name и prototype. Для маркированной таблицы наша основная заглушка виджета выглядит следующим образом:

Рекомендуется всегда использовать пространство имен для имен виджетов. В этом случае мы используем ‘ nt.bulletchart ‘. Все виджеты jQuery UI находятся в пространстве имен ‘ ui ‘. Хотя мы создаем пространство имен для виджета, вызов для создания виджета на элементе не включает пространство имен. Таким образом, чтобы создать диаграмму $('#elem').bulletchart() , мы бы просто $('#elem').bulletchart() .

Свойства экземпляра указываются после имени виджета. По соглашению, все закрытые методы виджета должны начинаться с префикса ‘_’. Есть некоторые специальные свойства, которые ожидаются фабрикой виджетов. К ним относятся options , _create , _destroy и _setOption .

  • options : это параметры по умолчанию для виджета
  • _create : Фабрика виджетов вызывает этот метод при первом создании экземпляра виджета. Это используется для создания исходного DOM и присоединения любых обработчиков событий.
  • _init : после вызова _create , фабрика вызывает _init . Обычно используется для сброса виджета в исходное состояние. Как только виджет создан, вызов конструктора простого виджета, например: $ .bulletchart () , также сбросит виджет. Это внутренне вызывает _init .
  • _setOption : Вызывается, когда вы устанавливаете опцию в виджете, с помощью вызова, такого как: $('#elem').bulletchart('option', 'size', 100) . Позже мы увидим другие способы настройки параметров в виджете.

Наш виджет Bulletchart оживает в методе _create . Вот где мы строим базовую структуру для диаграммы. _create можно увидеть ниже. Вы заметите, что здесь мало что происходит, кроме создания контейнера верхнего уровня. Фактическая работа по созданию DOM для баров, маркеров и тиков происходит в методе _setOption . Это может показаться несколько нелогичным, но для этого есть веская причина.

Обратите внимание, что столбцы, маркеры и отметки также можно изменить, установив параметры в виджете. Если бы мы сохранили код для его построения внутри _create , мы бы повторяли себя внутри _setOption . Перемещая код в _setOption и вызывая его из _create удаляет дублирование, а также централизуется конструкция.

Кроме того, приведенный выше код демонстрирует другой способ настройки параметров виджета. С _setOptions метода _setOptions (обратите внимание на множественное число) вы можете установить несколько параметров за один раз. Внутри фабрика будет выполнять отдельные вызовы _setOption для каждого из параметров.

Для _setOption метод _setOption является рабочей лошадкой. Он обрабатывает создание маркеров, баров и тиков, а также любые изменения, внесенные в эти свойства. Он работает путем очистки любых существующих элементов и воссоздания их на основе нового значения.

Метод _setOption получает ключ опции и значение в качестве аргументов. Ключ — это имя параметра, которое должно соответствовать одному из ключей в параметрах по умолчанию. Например, чтобы изменить столбцы в виджете, вы должны сделать следующий вызов:

Метод _setOption для маркера выглядит так:

Здесь мы создаем простой хэш имени опции для соответствующей функции. Используя этот хэш, мы работаем только с допустимыми параметрами и игнорируем недействительные. Здесь происходит еще две вещи: вызов _super() и запуск события _super() option. Мы рассмотрим их позже в этой статье.

Для каждого из параметров, которые изменяют DOM, мы вызываем определенный вспомогательный метод. Вспомогательные методы createBars , createMarkers и createTickBar указываются вне свойств экземпляра виджета. Это потому, что они одинаковы для всех виджетов и не должны создаваться отдельно для каждого экземпляра виджета.

Все функции создания работают в процентах. Это гарантирует, что диаграмма хорошо изменится при изменении размера содержащего элемента.

Без каких-либо параметров, указанных при создании виджета, будут действовать значения по умолчанию. Это роль свойства options . Для маркера наши параметры по умолчанию выглядят так:

Мы начинаем с размера 100% , без баров и маркеров и с тиками, размещаемыми каждые 10% . С этими значениями по умолчанию наша диаграмма маркера должна выглядеть так:

Таблица маркеров по умолчанию

До сих пор мы видели, как создать виджет с помощью _create и обновить его с помощью _setOption . Существует еще один метод жизненного цикла, который будет вызываться при уничтожении виджета. Это метод _destroy . Когда вы вызываете $('#elem').bulletchart('destroy') , фабрика виджетов внутренне вызывает _destroy для вашего экземпляра виджета. Виджет отвечает за удаление всего, что он ввел в DOM. Это может включать в себя классы и другие элементы DOM, которые были добавлены в метод _create . Это также хорошее место, чтобы отменить привязку любых обработчиков событий. _destroy должен быть полной противоположностью метода _create .

Для виджета с _destroy довольно прост:


Наш виджет Bulletchart почти завершен, за исключением одной последней функции: легенды . Легенда очень важна, так как она придаст больше значения маркерам и полосам. В этом разделе мы добавим легенду рядом с диаграммой.

Вместо того, чтобы добавлять эту функцию непосредственно в виджет Bulletchart, мы создадим подкласс bulletchart2 , который будет иметь поддержку легенды. В процессе мы также рассмотрим некоторые интересные особенности наследования Widget Factory.

Диаграмма с легендой

Фабрика виджетов поддерживает создание подклассов виджетов для создания более специализированных версий. Ранее в статье мы видели API для $.widget() , который имел три аргумента:

jQuery.widget(name[, base], prototype)

Второй параметр позволяет нам выбрать базовый класс для нашего виджета. Наш виджет bulletchart2 , который является подклассом bulletchart , будет иметь следующую подпись:

Здесь есть несколько интересных вещей:

  • Мы продолжаем пространство имен нашего имени виджета: nt.bulletchart2 .
  • Фабрика виджетов автоматически помещает виджет в пространство имен $ .nt . Таким образом, для ссылки на наш предыдущий виджет мы использовали $.nt.bulletchart . Точно так же, если бы мы $.ui.widget-name подкласс одного из стандартных виджетов jQuery UI, мы бы указали на них с $.ui.widget-name
  • widgetEventPrefix — это новое свойство, которого мы раньше не видели. Мы вернемся к этому, когда будем говорить о событиях. Остальные свойства экземпляра должны быть знакомы.

Поскольку мы добавляем больше элементов DOM с легендой, нам придется переопределить метод _create . Это также означает, что нам нужно переопределить _destroy , чтобы быть симметричным.

Здесь мы снова видим тот же шаблон, что и наш предыдущий метод _create . Мы создаем контейнер для легенды, а затем вызываем _setOption для создания остальной части легенды. Поскольку мы переопределяем _create , нам нужно убедиться, что мы вызываем базовый _create . Мы делаем это с помощью вызова _super . Точно так же в _destroy мы также видим вызов _super .

Теперь вы можете задаться вопросом: как виджет узнает, какой супер-метод вызывать с помощью простого неквалифицированного вызова _super ? Смарты для этого лежат в недрах фабрики виджетов. Когда виджет находится в подклассе, фабрика по- _super ссылку _super для каждой из функций экземпляра. Таким образом, когда вы вызываете _super из вашего метода экземпляра, он всегда указывает на правильный метод _super .

Поскольку сводная диаграмма поддерживает изменение маркеров и полос, легенда должна синхронизироваться с этими изменениями. Кроме того, мы также будем поддерживать переключение видимости маркеров и полос, щелкая элементы легенды. Это становится полезным, когда у вас есть несколько маркеров и баров. Скрывая несколько элементов, вы можете видеть другие более четко.

Для поддержки синхронизации легенды с изменениями маркеров и полос виджет bulletchart2 должен прослушивать любые изменения, происходящие с этими свойствами. Базовая диаграмма уже запускает событие change каждый раз, когда меняются его параметры. Вот соответствующий фрагмент из базового виджета:

Всякий раз, когда опция установлена, setOption событие setOption . Данные события содержат предыдущее и новое значение для опции, которая была изменена.

Прослушивая это событие в подклассе виджета, вы можете узнать, когда меняются маркеры или столбцы. Виджет bulletchart2 подписывается на это событие в своем методе _create . Подписка на события виджетов осуществляется с помощью вызова this.element.on() . this.element указывает на элемент jQuery, для которого был создан экземпляр виджета. Поскольку событие будет запущено для элемента, наша подписка на событие должна произойти на этом.

Обратите внимание на название события, используемого для подписки: 'bulletchart:setoption' . В качестве политики фабрика виджетов присоединяет префикс события к событиям, инициируемым из виджета. По умолчанию этот префикс является именем виджета, но его можно легко изменить с widgetEventPrefix свойства widgetEventPrefix . Базовый виджет Bulletchart меняет это на 'bulletchart:' .

Нам также необходимо подписаться на события 'click' на элементах легенды, чтобы скрыть / показать соответствующий маркер / панель. Мы делаем это с _on метода _on . Этот метод передает хэш сигнатуры события в функцию-обработчик. Контекст обработчика ( this ) правильно установлен на экземпляр виджета. Еще одно удобство с _on состоит в том, что фабрика виджетов автоматически отменяет привязку событий при разрушении.


Фабрика Widget включает в себя несколько других тонкостей, о которых вы должны знать.

До сих пор мы видели только один способ вызова методов в виджете. Мы сделали это с помощью $('#elem).bulletchart('method-name') . Однако это позволяет только вызывать открытые методы, такие как ‘option’, ‘destroy’, ‘on’, ‘off’. Если вы хотите вызывать эти методы непосредственно в экземпляре виджета, есть способ сделать это. Фабрика виджетов присоединяет экземпляр виджета к объекту data() элемента. Вы можете получить этот экземпляр так:

Кроме того, если вы хотите получить доступ ко всем виджетам Bulletchart на странице, есть также селектор для этого:

Есть несколько специальных методов, о которых вам следует знать, которые используются реже: _getCreateEventData() и _getCreateOptions() . Первый используется для прикрепления данных события для события ‘create’, которое запускается после завершения вызова _create .

_getCreateOptions — для добавления дополнительных параметров по умолчанию для виджета или переопределения существующих. Пользовательские параметры переопределяют параметры, возвращаемые этим методом, который, в свою очередь, переопределяет параметры виджета по умолчанию.


Это упаковка! Если вы хотите изучить дальше, ссылки ниже должны служить вам довольно хорошо. Конечно, лучшим источником информации всегда будет сам исходный код. Я бы рекомендовал прочитать исходный код jquery.ui.widget на GitHub.