Здравствуйте, хабровчане.
Хочу поделиться с вами одной техникой организации кода при массивной работе с DOM-элементами. Несколько лет назад, когда еще вовсе не было бэкбона и MVVC, мы писали старый добрый джаваскрипт без фреймворков: создавали объекты и заставляли их плясать на странице в общем танце. Такая практика, без сомнения, до сих пор оправдывает себя, и техника, о которой пойдет речь, применима именно к ней.
Мой рассказ — о маленькой библиотечке PageObject.js (текущая версия v0.14, 2.6K) и о том, как с ее помощью можно упростить себе жизнь.
Это не плагин jQuery, хотя, уверен, многие захотят ее назвать именно так. Это всего лишь функция, которая использует селекторы и кое-какие утилиты из jQuery, чтобы создать удобство в чтении и написании кода. По сути, это простая jQuery утилитка.
В создании объектов, которые манипулируют DOM-элементами, и их подключении на страницу ничего нового не придумаешь: создаем конструктор, сперва рендерим в нем определенный шаблон, затем разбираем его результат на части, «вешаем» на эти части обработчики событий, программируем остальную логику и встраиваем все это добро в наше приложение.
PageObject.js помогает с первыми двумя шагами.
После того, как отработает функция
Вот, пожалуйста, полный работающий пример с калькулятором. Мне же осталось рассказать подробнее о всех возможностях утилитки.
Первый аргумент должен быть объектом, у которого в последствии появится заполненый составными HTML-елементами неймспейс
Если НЕ указать опцию
Если указать
Если указать
Если НЕ указать
Когда
Когда
Если в вашем проекте нет underscore, вам нужно сконфигурировать
Если указана опция
И главное — селекторы. Если указать опцию
Если по селектору не будет найдено ни одного элемента — будет крик.
Если по селектору будет найдено более одного элемента — также будет исключение.
Если все же нужно, чтобы по селектору были найдены и помещены в массив более одного элемента, нужно к значению селектора дописать [] (пустые квадратные скобки) — такое выделение себя оправдывает.
Если нужно, чтобы множественные найденные елементы были помещены в объект (как в примере с калькулятором), значение селектора нужно записать в виде массива из двух элементов: первый элемент — собственно селектор, а второй — функция, которая из каждого найденого по указанному селектору элемента должна извлечь ключ (напр. айдишник) для помещения этого элемента в соответствующем неймспейсе.
Стоит отметить, что дополнительные неймспейсы в селекторах образуют неймспейсы с теми же именами внутри свойства
Пожалуй, на этом все.
Лучшее понимание того, что и как работает, вы сможете получить, почитав тесты и заглянув в исходник на гитхабе. Наверняка также будет полезной и общая документация.
Буду рад, если вы найдете данную технику и описанную выше конвенцию применимой и в ваших проектах. Особенно буду рад вашим пожеланиям и идеям, с радостью отвечу на вопросы.
Хочу поделиться с вами одной техникой организации кода при массивной работе с DOM-элементами. Несколько лет назад, когда еще вовсе не было бэкбона и MVVC, мы писали старый добрый джаваскрипт без фреймворков: создавали объекты и заставляли их плясать на странице в общем танце. Такая практика, без сомнения, до сих пор оправдывает себя, и техника, о которой пойдет речь, применима именно к ней.
Мой рассказ — о маленькой библиотечке PageObject.js (текущая версия v0.14, 2.6K) и о том, как с ее помощью можно упростить себе жизнь.
Это не плагин jQuery, хотя, уверен, многие захотят ее назвать именно так. Это всего лишь функция, которая использует селекторы и кое-какие утилиты из jQuery, чтобы создать удобство в чтении и написании кода. По сути, это простая jQuery утилитка.
Суть техники
В создании объектов, которые манипулируют DOM-элементами, и их подключении на страницу ничего нового не придумаешь: создаем конструктор, сперва рендерим в нем определенный шаблон, затем разбираем его результат на части, «вешаем» на эти части обработчики событий, программируем остальную логику и встраиваем все это добро в наше приложение.
function Calculator() {
if (this.constructor.name !== 'Calculator') { throw “No way, buddy!”; }
// 1. отрендерить шаблон
// 2. разобрать на части
// 3. повесить обработчики
// 4. остальная логика
}
PageObject.js помогает с первыми двумя шагами.
function Calculator() {
if (this.constructor.name !== 'Calculator') { throw “No way, buddy!”; }
var calc = this;
$.turnToPageObject(calc, {
template: $('#tmplCalculator').html(),
containerClass: 'calc',
context: {
caption: "Calculator"
},
selectors: {
buttons: [ ':button', Calculator.getButtonName ],
led: 'p'
}
});
// 3. повесить обработчики
// 4. другая логика
}
var calc = new Calculator;
$('body').append(calc.DOM.container);
После того, как отработает функция
$.turnToPageObject
(“превратить в объект страницы”), у объекта calc
появится свойство calc.DOM
— неймспейс, заполненый DOM-элементами, которые будут соответствовать указанным селекторам, и еще появится calc.DOM.container
— именно та легко встраиваемая в приложение часть объекта — контейнер всего-всего.Вот, пожалуйста, полный работающий пример с калькулятором. Мне же осталось рассказать подробнее о всех возможностях утилитки.
$.turnToPageObject
Первый аргумент должен быть объектом, у которого в последствии появится заполненый составными HTML-елементами неймспейс
DOM
. Второй аргумент — опции.Если НЕ указать опцию
container
, то контейнер будет создан (без него никак), и это будет такой же элемент, как и containerElement
(по умолчанию — DIV
).Если указать
containerClass
, то контейнеру будет присвоен класс.Если указать
template
, то будет отрендерен шаблон и его результат будет помещен внутрь контейнера.Если НЕ указать
context
, то шаблон будет отрендерен с пустым контекстом {}.template
может быть либо строкой, либо функцией (интеграция с Jammit JST). Когда
template
— функция, он принимает только контекст и должен возвратить строку.Когда
template
— строка, шаблон рендерится при помощи templateEngine
, которая автоматически настроится по умолчанию на использование шаблонизатора _.template
, если underscore присутствует. Если в вашем проекте нет underscore, вам нужно сконфигурировать
templateEngine
.// вот так меняются умолчания:
$.turnToPageObject.configure({
templateEngine: window.tmpl, // http://ejohn.org/blog/javascript-micro-templating
containerElement: 'strong'
});
templateEngine
принимает два аргумента — строку шаблона и контекст — и также должен возвратить строку.Если указана опция
hide
, то контейнер будет спрятан, что часто бывало удобно.И главное — селекторы. Если указать опцию
selectors
(объект), то соответствующие селекторам найденые в содержимом контейнера HTML-элементы будут по аналогичным ключам помещены в неймспейс DOM
. Если опция template
была указана, то селекторы будут искать в уже отрендеренном шаблоне. Если по селектору не будет найдено ни одного элемента — будет крик.
Если по селектору будет найдено более одного элемента — также будет исключение.
Если все же нужно, чтобы по селектору были найдены и помещены в массив более одного элемента, нужно к значению селектора дописать [] (пустые квадратные скобки) — такое выделение себя оправдывает.
Если нужно, чтобы множественные найденные елементы были помещены в объект (как в примере с калькулятором), значение селектора нужно записать в виде массива из двух элементов: первый элемент — собственно селектор, а второй — функция, которая из каждого найденого по указанному селектору элемента должна извлечь ключ (напр. айдишник) для помещения этого элемента в соответствующем неймспейсе.
Стоит отметить, что дополнительные неймспейсы в селекторах образуют неймспейсы с теми же именами внутри свойства
DOM
.Пожалуй, на этом все.
Лучшее понимание того, что и как работает, вы сможете получить, почитав тесты и заглянув в исходник на гитхабе. Наверняка также будет полезной и общая документация.
Буду рад, если вы найдете данную технику и описанную выше конвенцию применимой и в ваших проектах. Особенно буду рад вашим пожеланиям и идеям, с радостью отвечу на вопросы.