Как стать автором
Обновить

Создаем собственные виджеты в Dojo

Время на прочтение 6 мин
Количество просмотров 11K

Dojo Toolkit это одновременно самый мощный и наименее используемый JavaScript фреймворк. Dojo состоит из AMD модулей, большая часть которых является виджетами. Виджеты обычно состоят из логики на JavaScript и HTML шаблона. В будущей версии 2.0 заявлена поддержка WebComponents. Dojo позволяет легко как создать полностью новый виджет, так и расширить или изменить уже существующий. В этом посте я расскажу как это делать.

Создание простейшего виджета


Для начала создадим простейший виджет.

Step 1: Создание структуры

Для объявления своего виджета нужно создать JavaScript файл со следующим содержанием:
define([
      "dojo/_base/declare",
      "dijit/_Widget",
      "dijit/_TemplatedMixin"
], function(declare, _Widget, _TemplatedMixin){
  return declare([_Widget, _TemplatedMixin], {});
});

Пока мы просто объявили AMD модуль и указали несколько зависимостей. Первым аргументом функции declare является массив модулей от которых требуется унаследовать создаваемый модуль. Сейчас указано, что модуль наследует базовый для всех виджетов модуль dijit/_Widget и модуль _TemplatedMixin, который предоставляет шаблонизатор.

Step 2: Создание HTML представления

Создадим рядом с файлом модуля папку templates и в ней HTML файл. Назвать его лучше так же как и файл модуля. Пусть модуль называтся MyCustomWidget.js, тогда файл шаблона следует назвать MyCustomWidget.html. В файле шаблона должно находится HTML представление виджета. Причем корень обязательно должен быть один.

Шаблонизатор позволяет:

  • указать специальные узлы, attachPoints, которые будут доступны как свойства виджета;

    Для этого у нужного узла необходимо задать специальный атрибут: data-dojo-attach-point=”customNode”, где “customNode” — название свойства виджета через которое будет доступен узел. Корневой узел виджета всегда доступен через свойство domNode.

  • определить обработчики событий;

    Для этого у нужного узла необходимо задать специальный атрибут: data-dojo-attach-event=”ondijitclick:_onClick”, где “ondijitclick” указывает на событие, которое необходимо обрабатывать, в данном случае клик, а “_onClick” — название метода, который должен выступить в роли обработчика события.

  • указать место подстановки значений свойств виджета при его создании.

    Для этого в шаблоне нужно написать ${nameProp}, где “nameProp” — название свойства.


Step 3: Связываем шаблон и данные

Подключим шаблон:
define([
      "dojo/_base/declare",
      "dijit/_Widget",
      "dijit/_TemplatedMixin",
      "dojo/text!./templates/MyCustomWidget.html"
], function(declare, _Widget, _TemplatedMixin, template){
  return declare([_Widget, _TemplatedMixin], {
      templateString: template
  });
});

На самом деле мы могли и не выносить шаблон в отдельный файл, а сразу задать HTML как значение свойства templateString или вынести его в переменную, но, по-моему, это снижает красоту кода.

В качестве примера виджета создадим виджет выводящий фамилию и имя.
<div>
      <span data-dojo-attach-point="surnameNode">${surname}</span>
       
      <span data-dojo-attach-point="nameNode">${name}</span>
</div>

Чтобы каждый раз, когда у виджета изменяются свойства, менялись значения и в HTML, необходимо связать сеттеры свойств и attachPoints. Можно указать какое свойство какого attachPoint соответствует какому свойству виджета, а можно определить собственные сеттеры.

Если у вас есть свойство, где задание/получение значения сложнее чем просто обращение к свойству объекта, то вам нужно определить собственные сеттеры/геттеры соблюдая простые правила именования: для свойства “foo” это будут _setFooAttr/_getFooAttr. Методы set и get автоматически найдут их и вызовут в случае необходимости.
define([
      "dojo/_base/declare",
      "dijit/_Widget",
      "dijit/_TemplatedMixin",
      "dojo/text!./templates/MyCustomWidget.html"
], function(declare, _Widget, _TemplatedMixin, template){
  return declare([_Widget, _TemplatedMixin], {
      templateString: template,
      _setSurnameAttr: { node: "surnameNode", type: "innerHTML" },
      _setNameAttr: function(val){
              this.nameNode.innerHTML = val;
              this._set("name", val);
      }
  });
});


Как вы, наверно, уже могли догадаться, описанный виджет можно подключить используя его имя и расположение. Можно использовать прямой путь до JS-файла модуля, а можно объявить свой пакет, по аналогии с dojo, dijit и dojox, и подключать файлы из него. Альтернативой является сразу использовать результат вызова функции declare.

Как работает созданный нами код можно посмотреть здесь.

Виджет состоящий из других виджетов


Виджет может состоять из других виджетов. Составляющие виджеты можно добавить динамически во время создания виджета, но удобнее объявить их сразу в шаблоне. Для этого к модулям от которых наследуется виджет необходимо добавить dijit/_WidgetsInTemplateMixin.

В качестве примера шаблона рассмотрим фрагмент шаблона слайдера, который состоит из горизонтального ползунка и текстового поля ввода:

<div>
	<div>
		<div data-dojo-type="dijit/form/HorizontalSlider"
			data-dojo-attach-point="slider"
			name="${name}"
			value="${value}"
			maximum="${maximum}"
			minimum="${minimum}"
			step="${step}"
			showButtons="${showButtons}"
			intermediateChanges="${intermediateChanges}"
			style="width:150px">
		</div>
		<div data-dojo-type="dijit/form/TextBox"
			value="${value}"
			type="number"
			data-dojo-attach-point="textbox">
		</div>
		<span data-dojo-attach-point="legendNode"></span>
	</div>
	<div data-dojo-attach-point="descriptionNode"></div>
</div>

В этом фрагменте мы объявили виджет dijit/form/HorizontalSlider, который представляет собой горизонтальный ползунок, и виджет dijit/form/TextBox — текстовое поле ввода.

Все виджеты сразу вписаны в специальную разметку и обладают:
  • свойствами с фиксированными значениями;
  • свойствами, значения которых проброшены из виджета слайдера.

Также, мы снабдили вложенные виджеты атрибутами data-dojo-attach-point, чтобы можно было обращаться к ним, как к свойствам виджета. Т.е. если мы захотим получить значение поля ввода, то нам нужно написать:
this.textbox.get("value");

Аналогичный виджет из APS JS SDK можно увидеть в APS Fiddle.

Жизненный цикл виджета


Жизненний цикл виджета позволяет понять что именно и когда происходит.

Вы можете расширить или переопределить следующие методы:

  • constructor

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

  • параметры создания виджета смешиваются со значением свойств по умолчанию

    Данное действие нельзя переопределить, но важно знать когда это происходит.

  • postMixInProperties

    Данный метод вызывается перед тем как будет создано HTML представление виджета. Если нужно добавить или изменить свойства экземпляра виджета перед созданием его визуального представления — это лучшее место чтобы сделать это.

  • buildRendering

    dijit/_Templated предоставляет реализацию buildRendering, которой достаточно в большинстве случаев: загрузит и прочитает шаблон, создаст DOMElements, привяжет специальные узлы и события. Итоговый результат будет помещен в this.domNode. Если вы не используете dijit/_Templated, например, используете другой шаблонизатор, тогда это то место, где вы должны его использовать.

  • вызываются сеттеры

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

  • postCreate

    Основное место для дополнительной логики при создании виджета. Но, следует помнить, что в случае контейнерного виджета дочерние (не те, что объявлены в шаблоне) виджеты еще не добавлены и HTML представление еще не помещено в DOM.

  • startup

    Разбор и создание всех дочерних виджетов завершено. Виджет помещен в DOM.

  • destroy

    Реализуйте destroy, если вам нужно выполнить какие-то дополнительные действия при уничтожении виджета.


Inherited

При переопределии метода всегда полезно убедиться, что вы не потеряли нечто важное, что происходит в данном методе выше по цепочке наследования. Поэтому не забывайте вызывать this.inherited до или после вашего кода.
postCreate: function(){
   // do my stuff, then...
   this.inherited(arguments);
}


Полезные ссылки


Еще пример создания виджета.
Больше информации о создании виджетов.
Больше информации о жизненном цикле виджета.
Теги:
Хабы:
+14
Комментарии 19
Комментарии Комментарии 19

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн
PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн