Получается нужно постоянно выбирать, сравнивать все плюсы и минусы, или учить несколько фреймворков для разных проектов, для одного jquery, второго angular, а для будущего присматриваться к vue.js.
Было-бы здорово иметь один инструмент который может справиться со всеми требуемыми задачами, а именно:
- Встраиваться в уже отданную сервером страницу, без необходимости серверного рендеринга на node.js и возможность использования его с любыми другими библиотеками
- Иметь объектно-ориентированный, компонентный подход построения приложения, четкую и понятную структуру, возможность наследования свойств.
- Легкость в изучении, небольшой размер, производительность, возможность применять его как в маленьких так и больших проектах, а также для создания виджетов, слайдеров и т.д.
Как вы наверное уже догадались, здесь я как раз и хочу его представить htmlix.js
Фреймворк встраивается в уже отданную сервером страницу с помощью data- свойств.
Таким образом нам не нужно создавать шаблоны на каком либо другом языке в js коде, мы просто используем уже готовый html.
Далее создадим небольшое приложение, чтобы в сжатом виде познакомиться со всеми основными особенностями фреймворка.
Уже готовый, похожий пример можно покликать здесь.
После ввода имени пользователя в форму, приложение отобразит его имя в приветствии, кнопке выхода, отобразит сообщение о новом посетителе и создаст новый контейнер в массиве с пользователями, а также сохранит данные в localStorage. После перезагрузки страницы, возьмет имя из localStorage. При клике по кнопке выйти из профиля удалит данные со всех компонентов и переменную из localStorage и отобразит сообщение о выходе посетителя.
Давайте создадим четыре компонента: форму входа form, приветствие greeting, кнопку выхода logout и массив со всеми посетителями users_array.
Создадим html разметку всех компонентов:
<!-- компонент - контейнер форма с двумя свойствами input c типом свойства "inputvalue" и click с типом "click" --><form data-form="container" class="card col-12"> <div class="form-group"> <label for="">Введите имя</label> <textarea data-form-input="inputvalue" class="form-control" rows="1"></textarea> </div> <button data-form-click="click" type="submit">Submit</button></form><!-- компонент - контейнер приветствие и свойство user_name с типом - "text" --><div data-greeting="container" class="col-6 card"> <p>Привет: <span data-greeting-user_name="text">guest</span></p></div><!-- компонент - контейнер кнопка выхода и свойство user_name с типом - "text" --><div data-logout="container" class="col-6 card"> <a href="#"> Выйти из профиля: ( <span data-logout-user_name="text"></span> ) </a> </div><!-- компонент - массив пользователей, изначально с двумя контейнерами, в каждом контейнере свойство user_name - "text", и свойством массива message с типом "text" для отображения сообщений --> <div data-users_array="array"> <p data-users_array-message="text" > </p> <div class="row"> <div data-user="container" class="col-4 card"><p>пользователь - <span data-user-user_name="text">user_name_1</span> </p> </div> <div data-user="container" class="col-4 card"> <p>пользователь - <span data-user-user_name="text">user_name_2</span> </p> </div> </div></div>
В коде выше мы создали четыре компонента: три из них с типом container и один с типом array массив со всеми посетителями. Контейнер это компонент, в котором сгрупированы, какие либо html свойства, например текст, атрибут, слушатель события и т.д. Все свойства имеют определенный тип. Массив это компонент для работы с однотипными контейнерами, у массива так-же как и у контейнера могут быть различные свойства.
В примере выше мы указали свойства в html разметке с помощью data- атрибутов, также свойства можно указать с помощью селекторов из javascript кода, чтобы не писать их в разметке.
Теперь перенесем их в javascript:
var StateMap = { form: {//форма входа container: "form", props: ["input", "click"], methods: { click: function(){ event.preventDefault(); //отменяем перезагрузку страницы //this - указывает на свойство, в обработчике события которого мы находимся, parent - доступ к контейнеру из свойства //получаем данные свойства input var text = this.parent.props.input.getProp(); console.log(text); } }, }, greeting: {//приветствие container: "greeting", props: [ "user_name", ], methods: { } }, logout: { //кнопка выхода container: "logout", props: [ "user_name", ], methods: { }, }, users_array: { //массив с пользователями selector: "div.row", //уточняющий селекторarrayProps: [ "message"], //свойство массива container: "user", //контейнер массива props: [ "user_name", ], //свойство контейнера methods: { }, },}window.onload = function(){//создаем экземпляр приложения htmlix var HM = new HTMLixState(StateMap); console.log(HM); }
В примере выше мы перенесли компоненты в javascript код. В компоненте form свойстве click мы записываем данные введенные пользователем в переменную text и выводим их пока-что в консоль. Далее эти данные мы будем использовать во всех оставшихся компонентах. Для того чтобы компоненты узнали о том что данные обновились мы будем использовать пользовательские события.
Добавим событие emiter-set-name:
eventEmiters: { //добавляем объект со всеми пользовательскими событиями в описание приложения ["emiter-set-name"]: {prop: ""}, //событие с начальными данными},///вызываем событие в свойстве click компонента form и передаем в него полученные данныеclick: function(){ event.preventDefault(); var text = this.parent.props.input.getProp(); this.rootLink.eventProps["emiter-set-name"].setEventProp(text); //сохраняем имя пользователя в localStorage window.localStorage.setItem('user_name', name); } //слушаем событие во всех остальных компонентах и обновляем их свойстваgreeting: { container: "greeting", props: [ "user_name", ['listen_set_name', "emiter-set-name", "" ],], //создали свойство слушатель события в компоненте methods: { listen_set_name: function(){//получили данные из события и обновили свойство user_namethis.parent.props.user_name.setProp( this.emiter.getEventProp() ); } },},logout: { container: "logout", props: [ "user_name", ['listen_set_name', "emiter-set-name", "" ] ], methods: { listen_set_name: function(){//слушаем событие и обновляем свойство user_name this.parent.props.user_name.setProp( this.emiter.getEventProp() );}, },},users_array: { selector: "div.row",arrayProps: [ "message", ['listen_set_name', "emiter-set-name", ""],], arrayMethods: { listen_set_name: function(){//слушаем событие в свойстве массива и создаем новый контейнер с полученными данными this.parent.add( {user_name: this.emiter.getEventProp()} ); //выводим сообщение о новом посетителе this.parent.props.message.setProp("новый посетитель - "+this.emiter.getEventProp()); },container: "user",props: [ "user_name", ],methods: {}, },window.onload = function(){var HM = new HTMLixState(StateMap); //проверяем есть ли переменная user_name в localStorage и при ее наличии вызываем событие var name = window.localStorage.getItem('user_name');if(name != null)HM.eventProps["emiter-set-name"].setEventProp(name); console.log(HM);}
В коде выше мы создали пользовательское событие которое одновременно служит хранилищем для меняющихся данных, затем в каждом компоненте добавили свойство-слушатель данного события, чтобы при обновлении данных произвести изменения в каждом компоненте.
Теперь создадим событие emiter-exit-user для выхода пользователя:
eventEmiters: {/* ... */["emiter-exit-user"]: {prop: ""}, } //вызываем событие в компоненте logout и передаем в него имя пользователяlogout: { container: "logout", props: [ /* ... */, ["exit", "click", "a:first-of-type"],], //создали новое свойство - слушатель события "click" и указали его вторым способом с помощью массива methods: { /* ... */ exit: function(){ //получаем имя пользователя var user_name = this.parent.props.user_name; //вызываем событие this.rootLink.eventProps["emiter-exit-user"].setEventProp( user_name.getProp() ); //удаляем пользователя из localStorage window.localStorage.removeItem('user_name'); //очищаем свойство компонента user_name.setProp(""); }},},users_array: { selector: "div.row",arrayProps: [ /* .. */, ['listen_exit_user', "emiter-exit-user", ""], ], //добавили свойство - слушатель события "emiter-exit-user"arrayMethods: {/* ... */listen_exit_user: function(){//data - доступ ко всем контейнерам из массиваthis.parent.data.forEach(container=>{if(container.props.user_name.getProp() == this.emiter.getEventProp()){ container.remove(true); //удалили контейнер }}); //добавили сообщение this.parent.props.message.setProp( this.emiter.getEventProp()+" - покинул сайт");},},container: "user",props: [ "user_name", ],methods: {}, },greeting: {container: "greeting",props: [/* ... */, ['listen_exit_user', "emiter-exit-user", ""] ], methods: {listen_exit_user: function(){ //удалили имя пользователя из свойстваthis.parent.props.user_name.setProp("");}},},
Это был краткий обзор основных принципов построения приложения на htmlix, полный код данного примера, вместе с использованием вспомогательных методов можно посмотреть здесь