https://habr.com/ru/post/457370/- JavaScript
- Программирование
htmlix — микро фреймфорк на основе data- свойств. Из преймуществ это маленький размер, возможность четко структурировать код, наличие пользовательских событий для обновления DOM а также серверный рендеринг на всех языках по умолчанию, т. к. встраивается в существующюю структуру Html файла.
Сам фреймворк имеет объектно-ориентированную структуру, где каждое свойство — это объект. Получение, запись и удаление свойств происходит с помощью методов setProp(), getProp() и removeProp(), при этом в зависимости от типа свойства приложение само оприделит каким образом оно изменит данное свойство в html, если это класс то будет вызвана функция this.htmlLink.classList.add(«class»).
→ Готовый пример можно
посмотреть по ссылке
→ Код примера можно скачать
здесь (файлы top-menu-group.html, /js/top-menu-group.js)
Для подключения файлов в проект нужно скопировать папку htmlix по указанной выше ссылке.
Наше меню будет содержать различное количество подпунктов в каждом пункте, и два итоговых варианта ссылки: один это просто текст, второй вариант картинка и текст.
Для создания повторяющихся в html в разных местах и в разном количестве компонентов в htmlix используются виртуальные массивы и свойства с типом данных «group».
Виртуальный массив это массив не содержащий ссылки на Dom элемент с контейнерами которые могут содержать другие компоненты имеющие свойство с типом «render-type» или «group» — как в нашем случае.
Свойства group групируют в себе контейнеры из различных виртуальных массивов.
У нас будет 3-х уровневое меню, соответственно необходимо создать три массива — компонента,
один у нас будет обычный с названием «menu» и два виртуальных с названиями «menu_level_2»,
«menu_level_3».
В javascript это будет выглядеть так:
var State = {
menu: {//первый обычный массив ссылка в html - data-menu="array"
container: "item_level_1", // массив будет содержать контейнеры в html - data-item_level_1="container"
props: [ /*здесь будет список всех свойств*/],
methods:{
/*здесь будет список всех методов обработчиков событий*/
}
},
virtualArrayComponents: {//обьявляем обьект содержащий виртуальные массивы (не содержат ссылку на DOM)
menu_level_2:{// виртуальный массив, в html коде не присутствует
container: "item_level_2",//контейнер виртуального массива в html - data-item_level_2="container"
props: [/*здесь будет список всех свойств*/],
methods: {
}
},
menu_level_3:{//виртуальный массив
container: "item_level_3", //контейнер виртуального массива в html - data-item_level_3="container"
props: [ ],
methods: {
}
},
}}
Далее посмотрим как по отдельности будут выглядеть наши компоненты в html коде:
Массив menu:
<ul data-menu="array" class="nav-menu-3 pc-width">
<li data-item_level_1="container" data-item_level_1-over='mouseover' data-item_level_1-out='mouseout' >
<a href="#" >Пункт меню</a>
<ul class="hover-non" data-item_level_1-submenuclass="class" data-item_level_1-group="group" >
<!-- Здесь будут содержаться контейнеры data-item_level_2="container" из виртуального массива menu_level_2 - --->
</u>
</li>
</ul>
Здесь:
data-menu=«array» — ссылка на массив первого уровня;
data-item_level_1=«container» — ссылка на контэйнер массива;
data-item_level_1-over='mouseover' — будушее свойство over — обработчик события 'mouseover';
data-item_level_1-out='mouseout' — свойство out обработчик события 'mouseout';
data-item_level_1-submenuclass=«class» — свойство submenuclass — доступ к классам;
data-item_level_1-group=«group» — свойство для групировки контейнеров из виртуальных массивов — массив group[«group-children»] — содержит все обьявленные в html внутри тега — контейнеры data-item_level_2=«container» (все контейнеры item_level_2 — содержатся в виртуальном массиве menu_level_2 а в свойстве group только те которые обьявлены в этом конкретном свойстве контейнера data-item_level_1);
Виртуальный массив menu_level_2
<!-- контейнер виртуального массива -->
<li data-item_level_2="container" data-item_level_2-over='mouseover' data-item_level_2-out='mouseout'>
<a href="#">строка меню</a>
<ul class="hover-non" data-item_level_2-submenuclass="class" data-item_level_2-group_2="group">
<!-- Здесь будут содержаться контейнеры data-item_level_3="container" из виртуального массива menu_level_3 - --->
</ul>
</li>
Здесь:
data-item_level_2=«container» — ссылка на контэйнер виртуального массива menu_level_2;
data-item_level_2-over='mouseover' — будушее свойство over — обработчик события 'mouseover';
data-item_level_2-out='mouseout' — свойство out обработчик события 'mouseout';
data-item_level_2-submenuclass=«class» — свойство submenuclass — доступ к классам;
data-item_level_1-group_2=«group» — свойство для групировки контейнеров из следующих виртуальных массивов menu_level_3 и menu_level_3_img(который мы еще не создали)
Виртуальные массивы menu_level_3 и menu_level_3_img по тому же принципу:
<li data-item_level_3="container">
<a href="#">item-level-3</a>
</li>
<li data-item_level_3_img="container">
<a href="#"><img src="/img/Thumbnail_300x300.png">item-level-3</img></a>
</li>
Они не содержат свойств, только ссылку на html контейнер, но в будущем их можно будет добавить, если возникнет необходимость.
Теперь отредактируем javascript код добавив все свойства и одноименные обработчики к свойствам-событиям
Полностью готовый код будет выглядеть так:
var State = {
menu: {
container: "item_level_1",
props: [ "submenuclass", "group", "over", "out"],//добавили список свойств
methods:{ //добавили два обработчика к свойствам "over", "out"
over: function(){
//this - в обработчике указывает на конкретный dom элемент (this.htmlLink) и его свойство
//получаем доступ к родительскому контейнеру и смежному свойству submenuclass с нашим свойством (находящемся в общем контейнере), после чего удаляем класс "hover-non" чтобы отобразить подпункт меню.
this.parentContainer.props.submenuclass.removeProp("hover-non");
},
out: function(){
this.parentContainer.props.submenuclass.setProp("hover-non");
},
}
},
virtualArrayComponents: {//виртуальные массивы
menu_level_2:{
container: "item_level_2",
props: [ "group_2", "submenuclass", "over", "out"],
methods: {
click: function(){ //аналогичная функция.
this.parentContainer["group-parent"].removeFromGroup(this.parentContainer["group-id"]);//.clearGroup();//
console.log(this.rootLink.state);
},
over: function(){
this.parentContainer.props.submenuclass.removeProp("hover-non");
},
out: function(){
this.parentContainer.props.submenuclass.setProp("hover-non");
},
}
},
menu_level_3:{
container: "item_level_3",
props: [ ],
methods: {
}
},
menu_level_3_img:{
container: "item_level_3_img",
props: [ ],
methods: {
}
},
},
eventEmiters: {
}
}
window.onload = function(){
///создаем экземпляр HTMLix
var HM = new HTMLixState(State);
console.log(HM);
}
Вот в принципе и весь javascript-код.
Html-код с уже помещенными в друг друга компонентами будет выглядеть так:
<nav >
<ul data-menu="array" class="nav-menu-3 pc-width">
<!--контейнер из массива menu -->
<li data-item_level_1="container" data-item_level_1-over='mouseover' data-item_level_1-out='mouseout' >
<a href="#" >Пункт меню</a>
<ul class="hover-non" data-item_level_1-submenuclass="class" data-item_level_1-group="group" ><!--class="sub-nav-menu"-->
<!--контейнер из виртуального массива menu_level_2 -->
<li data-item_level_2="container" data-item_level_2-over='mouseover' data-item_level_2-out='mouseout'>
<a href="#">строка меню</a>
<ul class="hover-non" data-item_level_2-submenuclass="class" data-item_level_2-group_2="group">
<!--контейнер из виртуального массива menu_level_3_img -->
<li data-item_level_3_img="container">
<a href="#"><img src="/img/Thumbnail_300x300.png">item-level-3</img></a>
</li>
<li data-item_level_3_img="container">
<a href="#"><img src="/img/Thumbnail_300x300.png">item-level-3</img></a>
</li>
<li data-item_level_3_img="container">
<a href="#"><img src="/img/Thumbnail_300x300.png">item-level-3</img></a>
</li>
</ul>
</li>
<li data-item_level_2="container" data-item_level_2-over='mouseover' data-item_level_2-out='mouseout'>
<a href="#">строка меню</a>
<ul class="hover-non" data-item_level_2-submenuclass="class" data-item_level_2-group_2="group">
<li data-item_level_3_img="container">
<a href="#"><img src="/img/Thumbnail_300x300.png">item-level-3</img></a>
</li>
<li data-item_level_3_img="container">
<a href="#"><img src="/img/Thumbnail_300x300.png">item-level-3</img></a>
</li>
</ul>
</li>
<!-- далее по тому же принципу в зависимости от нужного нам количества пунктов и подпунктов меню -->
Методов в фремворке пока не очень много, с ними можно познакомиться посмотрев исходный код где есть краткое описание к основным используемым в ходе работы. Пока что htmlix находится в тестовой версии, однако уже сейчас с помощью него можно решать многие типовые задачи фронтенд разработки.
Краткая документация по всем основным свойствам а также туториалы к некоторым примерам приложений можно почитать
здесь.