habrahabr

Для чего был создан новый javascript framework htmlix

  • воскресенье, 13 октября 2019 г. в 00:32:09
https://habr.com/ru/post/471246/
  • JavaScript


Добрый день в данной cтатье попытаюсь рассказать для чего был создан новый js frontend framework Htmlix. В общем возможно кто-то скажет что это очередной велосипед, но не суть, попытка вникнуть в работу большинства js фреймворков осталась безуспешной. Потому как требовала слишком большого времени и сил на их освоение, ну и слишком большая избыточность кода не дает полный контроль над инструментом который я хотел освоить для работы. Поэтому попробовав написать что-то на каждом из них, я так и не определился на конкретном тем-более, что постоянно придумывают что-то новое и не факт, что сегодня выучив один, завтра не прейдется учить новый более модный фреймворк.

Из недостатков существующих решений это отсутствие серверного рендеринга на php и возможности работать в связке с такими серверными решениями как например wordpress поэтому была поставлена задача создать что-то что встраивается в уже отданную сервером статическую страницу на каком бы языке она не была написана без необходимости серверного рендеринга на js и дублирования части кода и файлов фреймворка на сервер. Что-то на подобе jquery но с более структурированным кодом и возможностью делать как большый так и маленькие приложения, а также меню и всякую мелочь для сайтов, чтото универсальное что будет подходить для всех основных задачъ фронтенд разработки.

Поэтому было решено написать свой собственный микро фреймворк, который возможно полностью контролировать, чтобы он был не слишком большой и прост в понимании и освоении.

Скачать Htmlix а также сопутствующие примеры приложений можно здесь

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

Разница в том что массивы и свойства мы объявляем не в js коде а в html поэтому они уже готовы и нет необходимости ждать когда код построит страницу, она уже отдается такой какая должна быть согласно данному url адресу, а затем фреймворк просто ищет соответствующие массивы и контейнеры и создает к ним ссылки для будущего обновления интерфейса при наступлении событий.

Например если мы хотим добавить обработчик событий то в html коде мы добавляем data свойство с именем обработчика и типом свойства в кавычках например создадим кнопку с обработчиком события click и параграф с текстом который изменится после клика на кнопку <button data-todoinput-clickone=«click» ...>

здесь первым идет название контейнера(todoinput — контейнер это div элемент который содержит в себе все свойства он выступает в роли хранилища для свойств), затем название свойства (clickone) а далее тип события «click». Второе свойство у нас не является событием, это просто текст который нужно будет изменить после клика по кнопке.

Тип свойства указывается для того чтобы фреймворк мог определить каким образом с ним работать если это событие, то указывается название события, таким образом фреймворк автоматически добавит обработчик события click нам необходимо будет только добывить функцию для обработки в js коде.

Html код данного приложения будет выглядеть так:

         <div data-todoinput="container" >
			<button  data-todoinput-clickone="click"> >></button>
                        <p data-todo-paragraf="text" >до клика </p>
       </div>
   

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

       var State = {
	       todoinput: {
		      container: "todoinput",
		      props: ["paragraf",  "clickone"],
		      methods:{ 
                             clickone: function(event){
				    this.parent.props['paragraf'].setProp("Новый текст"),
                               }
                      }
        }


         window.onload = function(){
                 ///создаем экземпляр  HTMLix

        var HM = new HTMLixState(State); ///создаем экземпляр приложения после загрузки 
    страницы.
        console.log(HM);
        }

В коде выше мы указали контейнер todoinput в нем два свойства props: [«paragra», «clickone»], а для свойства обработчика событий добавили функцию в объекте methods. В самой функции доступ к другим свойствам общего контейнера осуществляется с помощью оператора this далее имя контейнера, а затем в обьекте props имя свойства, ну а далее с помощью .setProp меняем надпись на новую. То есть навигация из конкретного свойства в другое осуществляется таким вот простым способом. Если например нам нужно попасть в свойство другого контейнера можно просто написать: this.rootLink.state.имя-контейнера.props[«имя свойства»]

Структура

Структура приложения это контейнеры в которых содержатся свойства, если нам нужно много однотипных контейнеров, таких как например список пунктов todo mvc, то они помещаются в массивы, и могут удаляться и создаваться новые по шаблону, доступ к конкретному контейнеру в массиве осуществляется похожим способом: this.rootLink.state.имя-массива.data[порядковый-номер].props[«имя свойства»].

Благодаря этому мы имеем легко структурированный понятный код, с простым доступом ко всем необходимым нам свойствам.

Изменение состояния и обновление переменных

Для изменения состояния приложения используются пользовательские события eventEmiters
которые также как и обычные события вызывают функции на всех слушателях, которые могут записать обновленные данные при наступлении события:

Например создадим переменную которая содержит количество кликов по кнопке и два параграфа которые отображают количество кликов:

         <div data-todoinput="container" >
			<button  data-todoinput-clickone="click"> >></button>
                        <p data-todo-paragraf="text" >до клика </p>
       </div>

       <!------------ добавим два парагафа в массив --> 
         <div data-paragrafs="array" >

		    <div data-paragraf="container" data-paragraf-listner_click="emiter-click" >
                           <p data-paragraf-paragraf_text="text" >0</p>
                     </div>
		    <div data-paragraf="container" data-paragraf-listner_click="emiter-click">
                           <p data-paragraf-paragraf_text="text" >0</p>
                     </div>
       </div>

   

Добавили каждому параграфу слушатель события «emiter-click», в js коде это будет выглядеть так:

       var State = {
	       todoinput: {
		      container: "todoinput",
		      props: ["paragraf",  "clickone"],
		      methods:{ 
                             clickone: function(event){
				    this.parent.props['paragraf'].setProp("Новый текст");
                                    
                                   ///после клика обновили пользовательскую переменную и вызвали пользовательское событие

                                    this.rootLink.eventProps["emiter-click"].setEventProp( this.rootLink.eventProps["emiter-click"].getEventProp + 1);


                               }
                      },
                paragrafs: { //имя массива
                       container: "paragraf", //имя контейнера
                        props: ["paragraf_text",  "listner_click"],
      		      methods:{ ///далее метод для пользовательского события который меняет количество кликов в параграфе каждого контейнера
                            listner_click: function(event){

                                   //получаем обновленное значения переменной
                                    var prop = this.rootLink.eventProps["emiter-click"];

                                    //устанавливаем новое значение
				    this.parent.props['paragraf_text'].setProp(prop),
                               }
                      },          

                  },
////объект с начальными данными для пользовательских событий
	       eventEmiters: {
		
		 ['emiter-click'] : {		
			 prop: 0,
		
		   },

              }
        }


         window.onload = function(){
                 ///создаем экземпляр  HTMLix

        var HM = new HTMLixState(State); ///создаем экземпляр приложения после загрузки 
    страницы.
        console.log(HM);
        }

Изменение свойств

Свойства как вы могли уже заметить меняются с помощью сеттеров и геттеров (.setProp, .getProp, .removeProp), простота данного способа заключается в том, что нет необходимости запоминать названия для изменения каждого типа свойств, например для свойства с типом данных текст изменится текст в параграфе, а для свойства с типом «class» добавится или удалится класс в данном свойстве.

Роутер

Если нам необходимо сделать что-то более сложное чем просто todo mvс или «менюшки», можно использовать роутер который проверяет текущий адрес страницы и на основании его загружает и строит приложение, кому интересно туториал можно почитать в здесь

Размер

На данный момент размер фреймворка составляет 44kb, весь исходный код это 6 js файлов в папке htmlix-objects, так что если захотеть можно разобраться в принципе его работы и при возникновении потенциальных ошибок иметь возможность полного контроля над ситуацией.

Скачать Htmlix а также сопутствующие примеры приложений можно здесь.