Я не люблю писать Javascript. К сожалению, это необходимо, если вы хотите создавать интерактивные реактивные веб-сайты, или нет? Что, если есть способ реализовать многие преимущества Javascript на вашем веб-сайте без написания кода Javascript?
htmx — это небольшая библиотека, предоставляющая ряд функций Javascript — AJAX, WebSockets, проверка формы, анимация и другие — для записи в виде гипертекста в HTML. Никаких тегов сценария, никакого импорта библиотек (кроме сценария htmx), никакого управления пакетами. Только все наиболее распространенные интерактивные функции Javascript, которые используются в большинстве веб-приложений.
Вот как реализовать анимированный индикатор выполнения с помощью функции опроса загрузки htmx в приложении Rails. Пример довольно упрощенный — при нажатии кнопки Пуск индикатор выполнения будет постепенно заполняться каждую секунду в общей сложности на десять секунд. По прошествии каждой секунды полоса заполняется на десять процентов. По завершении появится кнопка, позволяющая начать весь процесс заново.
Добавьте htmx в Rails
Встроить библиотеку htmx очень просто — просто включите скрипт перед закрывающим тегом body в app/views/layouts/application.html.erb
:
... <body> <div class="container"> <%= yield %> </div> <!-- htmx --> <script src="https://unpkg.com/[email protected]"></script> <!-- end htmlx --> </body> ...
Добавьте контроллер
Я создал один контроллер с именем ProgressBarController
для выполнения трех необходимых действий — #index
, #start
и #job
:
- Действие index отображает страницу со всеми элементами управления пользовательского интерфейса;
- Действие запуска инициализируется и представляет индикатор выполнения и скрывает кнопку запуска;
- Наконец, действие задания будет обновлять индикатор выполнения в течение десяти итераций, а затем завершится.
class ProgressBarController < ApplicationController # DEVELOPMENT PURPOSES ONLY skip_before_action :verify_authenticity_token def index; end def start @percent = 0 render partial: 'progress' end def job @percent = params[:percent].to_i @percent += 10 render partial: 'finished' and return if @percent >= 100 render partial: 'progress' end end
В действии start
переменная @percent
инициализируется значением 0, которое затем становится доступным для партиала _progress
.
Действие job
загружает процентное значение из параметров запроса URL в переменную `@percent`
, а затем увеличивает его на 10. Если @percent
достигает 100, индикатор выполнения заполняется, и задание завершается, поэтому отрисовывайте частичный _finished
. Если индикатор выполнения не заполнен/завершен, повторите рендеринг партиала _progress
.
Настроить маршрутизацию
Маршрутизация проста; нужно только три. /progress_bar
перенаправит к основному действию HTML индекса. /progress_bar/start
и /progress_bar/job
перенаправят к соответствующим действиям в контроллере.
Обратите внимание, что /progress_bar/start
использует глагол POST, потому что он запускается кнопкой.
Rails.application.routes.draw do # htmx Progress Bar get '/progress_bar', to: 'progress_bar#index' post '/progress_bar/start', to: 'progress_bar#start' get '/progress_bar/job', to: 'progress_bar#job' end
Создайте представления
В этом приложении есть три вида; один основной вид и два частичных. Главный вид, app/views/progress_bar/index.html.erb
, содержит все контроллеры и встроен в компоновку.
<h1>htmx Progress Bar</h1> <div class="mt-5" hx-target="this" hx-swap="outerHTML"> <p>Click the Start Job button to start the progress bar. It will run for 10 cycles, incrementing by 10 % each cycle.</p> <button type="button" class="btn btn-primary" hx-post="/progress_bar/start"> Start Job </button> </div>
Обратите внимание на два атрибута htmx во внешнем <div>
, окружающем заголовок и кнопку. Директивы hx-target="this" hx-swap="outerHTML"
означают, что любое манипулирование DOM, вызванное действием htmx, полностью перезапишет этот тег <div>
(а не только HTML внутри тега — это будет innerHTML
).
Кнопка также содержит директиву htmx; hx-post
. Когда кнопка нажата, htmx вызовет URL-адрес /progress_bar/start
, используя AJAX.
Волшебство происходит, когда эти теги объединяются. директивы htmx наследуются. В большинстве случаев вложенные атрибуты htmx получат директивы, объявленные их родителями. В приведенном выше примере кнопке не нужно объявлять атрибуты target или swap. Он унаследует hx-target
и hx-swap
от своего родительского тега <div>
.
Комбинированные объявления htmx в этом примере означают, что при нажатии кнопки htmx вызовет /progress_bar/start
и поменяет/заменит содержимое в <div>
выводом вызова.
Партиал _progress
отображает индикатор выполнения и содержит больше атрибутов htmx:
<div class="mt-5" hx-target="this" hx-get="/progress_bar/job?percent=<%= @percent %>" hx-trigger="load delay:600ms" hx-swap="outerHTML"> <p>Running...</p> <div class="progress"> <div id="pb" class="progress-bar" style="width:<%= @percent %>%"> </div> </div>
Атрибуты hx-target
и hx-swap
описаны выше. hx-get
указывает htmx выполнить запрос GET на конечной точке /progress_bar/job
, предоставляя процент в качестве параметра запроса.
Когда будет выполнен этот запрос GET? Это определяется hx-trigger
. В этом случае он будет срабатывать каждые 600 миллисекунд.
Когда индикатор выполнения заполнен, действие ProgressBar#job
отобразит частичный _finished
, а не _progress
. Он отобразит полный индикатор выполнения вместе с кнопкой, чтобы снова перезапустить индикатор выполнения.
<div class="mt-5" hx-target="this" hx-swap="outerHTML"> <p>Complete! Press <strong>Restart Job</strong> to start the progress bar again.</p> <div class="progress"> <div id="pb" class="progress-bar" style="width:100%"> </div> </div> <button id="restart-btn" class="btn btn-primary mt-3" hx-post="/progress_bar/start" classes="add show:600ms"> Restart Job </button>
Как и на главной странице, при нажатии кнопки на этой странице htmx запускает POST очень на /progress_bar/start
и заменяет верхний уровень <div>
ответом.
Результат
Наш анимированный индикатор выполнения готов. Запустите сервер Rails, перейдите на страницу индекса и нажмите кнопку запуска, чтобы начать процесс.
Самое приятное то, что я не писал никакого Javascript для реализации индикатора выполнения — все было сделано путем простого добавления нескольких атрибутов к существующим тегам HTML.
Индикатор выполнения, показанный в этой статье, довольно упрощен и сам по себе не предоставляет никакой полезной функции. В следующей статье я покажу, как интегрировать индикатор выполнения с фоновым рабочим процессом, реализованным в Sidekiq, где панель предоставляет оперативные обновления на основе прогресса рабочего процесса.
Весь код доступен в моем проекте RailsScratch на Github. Пожалуйста, обратитесь туда за исходным кодом для этой и других демонстраций Rails и htmx. Обратите внимание, что по мере роста и развития репозитория некоторые примеры в этой статье могут отличаться от версий, перечисленных в этой статье.
Если вы заметили какие-либо ошибки или у вас есть предложения, как сделать содержание более понятным и точным, свяжитесь со мной. Я приветствую все отзывы.