Разработка одностраничных приложений с помощью HappyX

от автора

В прошлой статье я сравнивал HappyX и Karax, показывая их декларативный подход к разработке с помощью Nim.

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

Обложка веб-фреймворка HappyX

Обложка веб-фреймворка HappyX

Так как в прошлой статье сравнивался лишь сам код, я начну с того, как установить HappyX. Для начала необходимо поставить сам Nim, если он у вас стоит — отлично.

Следующий шаг — установка HappyX с помощью пакетного менеджера nimble. Ставим последнюю версию:

nimble install happyx@#head

Отлично, можно проверить установленную версию с помощью

hpx -v

При желании можно поставить любую другую версию, например для установки версии 3.5.2 нужно ввести команду nimble install happyx@3.5.2

Теперь можно переходить к созданию проекта. Для этого достаточно перейти в нужную вам директорию и ввести следующую команду.

hpx create --kind HPX --name project --use-tailwind
  • --kind HPX — выбор типа проекта, в данном случае мы выбрали одностраничное приложение с поддержкой .hpx файлов.

  • --name project — выбор имени для проекта.

  • --use-tailwind — для одностраничного приложения мы также можем включить поддержку Tailwind CSS 3.

В созданном проекте можно наблюдать файл src/main.hpx (в исходный код добавлены комментарии):

<template>   <div>     <!-- Использование компонента HelloWorld -->     <!--       Передача параметров:       userId как целое число,       query и pathParam как строки     -->     <HelloWorld userId:int="10" query="meow" pathParam="Path Param Example"></HelloWorld>   </div> </template>

Также в файле src/components/HelloWorld.hpx можем видеть следующее:

<template>   <div>     Hello, world! {self.userId} <!-- Подстановка значений из текущего компонента -->     <p>       Query is       {self.query}     </p>     <p>       pathParam is       {self.pathParam}     </p>   </div> </template>   <!--   Объявление скрипта, по желанию можно использовать здесь JavaScript,   указав lang="javascript" --> <script> # Здесь можно писать на Nim echo "Hello, world!"  # Здесь задаются пропсы компонента, которые можно передавать из других компонентов # Пропсам также можно задавать значение по умолчанию, как написано ниже props:   userId: int = 0   query: string = ""   pathParam: string = "" </script>  <!-- Изолированная область стилей, применяемая только для данного компонента --> <style>   .div {     border-radius: 4px;     background-color: #212121;     color: #ffffff;   } </style>

Помимо .hpx файлов в папке src находятся index.html и router.json. В первом нет ничего интересного кроме подключения скомпилированного js файла, а вот со вторым разберемся подробнее:

{   "/": "main.hpx",   "/user{ARG1:int}/{ARG2?:string}": {     "component": "HelloWorld",     "args": {       "userId": "ARG1",       "query": {         "name": "q",         "type": "query"       },       "pathParam": {         "name": "ARG2",         "type": "path"       }     }   } }

В файле router.json описаны маршруты вашего приложения, здесь вы можете изменять маршруты, задавать точки входа компонентов а также задавать параметры к маршрутам (query либо path).

Для того, чтобы запустить проект, достаточно находиться в папке с проектом (cd project). Теперь вы сможете наблюдать все изменения файлов в реальном времени.

hpx dev --reload

Попробуем изменить src/main.hpx следующим образом и сохранить файл:

<template>   <div>     <h1 h-if="self.showTitle()">       Добро пожаловать!     </h1>     <h1 h-else>       Скрытый заголовок     </h1>   </div> </template>  <script> <!-- Объявим метод компонента - showTitle --> proc showTitle(): bool =   true </script>

В <template></template> можем наблюдать применение директив h-if и h-else, некие аналоги v-if и v-else из Vue.js. В <script></script> находится объявление метода showTitle, который возвращает true.

Результат измененного src/main.hpx

Результат измененного src/main.hpx

Как можно видеть — отображается лишь «Добро пожаловать!«. Это происходит потому, что метод showTitle() всегда возвращает true.

Попробуем изменить скрипт:

<script> import random  randomize()  proc showTitle(): bool =   rand(100) > 50 </script>

Здесь мы добавили импорт стандартной библиотеки Nim — random, далее единожды вызываем функцию randomize(), теперь метод showTitle будет возвращать случайное значение. Попробуйте перезагрузить страницу несколько раз. Каждый раз надпись меняется!

Теперь попробуем реализовать собственный компонент, который будем использовать в src/main.hpx. Пусть этот компонент будет обычным счетчиком. Создадим файл src/components/Counter.hpx и запишем в него следующее:

<template>   <div class="flex justify-around rounded-md border-2 border-gray-900 bg-gray-300 px-2 w-24">     <div class="flex w-full self-center">{self.count}</div>     <div class="flex flex-col text-sm">       <button h-onclick="self.increase()">?</button>       <button h-onclick="self.decrease()">?</button>     </div>   </div> </template>  <script> # Объявляем пропсы props:   count: int = 0  # Метод для увеличения счетчика proc increase() =   self.count += 1  # Метод для уменьшения счетчика proc decrease() =   self.count -= 1 </script>

В этом компоненте мы используем новую директиву — h-onclick. С помощью нее мы можем обращаться к методам либо писать какой‑то короткий Nim код.

Теперь обновим файл src/main.hpx, чтобы использовать в нем наш счетчик:

<template>   <div>     <h1 h-if="self.showTitle()">       Добро пожаловать!     </h1>     <h1 h-else>       Скрытый заголовок     </h1>     <div class="p-2">       <Counter></Counter>     </div>   </div> </template>

Как вы видите — достаточно лишь использовать тег <Counter></Counter>, чтобы использовать наш компонент. Также мы можем передать в него начальное значение счетчика:

<div class="p-2">   <!--     При передаче указываем, что это целое число,     так как count в компоненте - целое число   -->   <Counter count:int="5"></Counter> </div>

Ниже можно видеть результат, который у нас получился:

h-if и два счетчика

h-if и два счетчика

Добавим также верхний и нижний порог счетчика:

<script> # Объявляем пропсы props:   count: int = 0   floor: int = int.low   ceil: int = int.high  # Метод для увеличения счетчика proc increase() =   if self.ceil <= self.count:     return   self.count += 1  # Метод для уменьшения счетчика proc decrease() =   if self.floor >= self.count:     return   self.count -= 1 </script>

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

Посмотрим, как это выглядит в src/main.hpx:

<div class="p-2">   <Counter count:int="5" floor:nim="0" ceil:nim="10"></Counter> </div>

Тут мы добавили передачу порогов с указанием :nim, с помощью которого тип автоматически распознается.


Маршрутизация

Теперь перейдем к маршрутизации, и, возвращаясь к src/router.json сразу добавим новый маршрут, по которому будет доступен только компонент с нашим счетчиком, при это мы сможем передавать ему значения.

{   "/": "main.hpx",   "/user{ARG1:int}/{ARG2?:string}": {     "component": "HelloWorld",     "args": {       "userId": "ARG1",       "query": {         "name": "q",         "type": "query"       },       "pathParam": {         "name": "ARG2",         "type": "path"       }     }   },   "/counter/{value:int}": {     "component": "Counter",     "args": {       "count": "value"     }   } } 

Теперь попробуем зайти на http://localhost:5000/#/counter/10:

страница со счетчиком

страница со счетчиком

Попробуйте поиграться с адресной строкой — значение меняется.

Теперь добавим маршрут, в котором можно регулировать порог счетчика:

"/counter/{value:int}": {   "component": "Counter",   "args": {     "count": "value"   } }, "/counter/{value:int}/{floor:int}-{ceil:int}": {   "component": "Counter",   "args": {     "count": "value",     "floor": "floor",     "ceil": "ceil"   } }

Таким образом можно настраивать маршруты любой сложности и взаимодействовать с ними.

Директивы

В примерах выше уже были использованы директивы h-if и h-else, однако кроме них также есть ряд директив.

h-if, h-elif, h-else служат для условного рендеринга:

<template>   <h1 h-if="5 > 10">5 больше 10</h1>   <h1 h-elif="5 == 10">5 = 10</h1>   <h1 h-else>5 меньше 10</h1> </template>

директива h-for служит для цикличного рендеринга:

<template>   <div>     <div h-for="i in [1, 2, 3, 4]">       {i}       <div h-for="j in i..10">         {i + j}       </div>     </div>   </div> </template>

Помимо h-for для цикличного рендеринга может использоваться h-while:

<template>   <script lang="nim">     # Здесь мы пишем на Nim     var x = 1   </script>   <div class="flex">     <div h-while="x <= 3">       {x}       <script lang="nim">         # Здесь мы пишем на Nim         x += 1       </script>     </div>   </div> </template>

Также существуют директивы для обработки событий. Они начинаются с h-on, например

  • h-onclick — обрабатывает нажатие мыши на элемент (click event);

  • h-onmouseover — срабатывает при наведении мыши на элемент (mouseover event);

  • h-onwheel — срабатывает при прокрутке колесика мыши (wheel event).

В каждом обработчике событий можно отправлять Event.

<template>   <div>     <button h-onclick="echo event.MouseEvent.x" h-onmouseover="echo event.MouseEvent.x">       Click!     </button>     <input placeholder="edit text ..." h-oninput="echo event.target.value" />   </div> </template>

Заключение

Императивный подход к разработке в HappyX все еще находится в разработке, однако уже предоставляет некоторый функционал, в том числе маршрутизацию, директивы для отрисовки элементов, компонентный подход а также обработку событий. При этом Nim используется как основной язык для разработки.

Ссылки

Прошлая статья о сравнении HappyX и Karax.

GitHub репозиторий.

Официальный сайт с документацией, написанный на HappyX.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Над чем стоит поработать в HappyX, чтобы сделать его лучше?

57.14% Документация4
42.86% Серверная часть3
14.29% Клиентская часть1
14.29% Привязки к другим языкам1
0% Свой вариант в комментариях0
57.14% Посмотреть результаты опроса4

Проголосовали 7 пользователей. Воздержались 4 пользователя.

ссылка на оригинал статьи https://habr.com/ru/articles/778222/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *