Введение
Динамичные и интерактивные веб-приложения уже давно создаются на JavaScript.
Создадим элегантное приложение — список задач, которое, если отмечать пункты галочками, мгновенно обновляется без перезагрузки всей страницы. И никакого JavaScript, только Golang и htmx. Благодаря этой мощной комбинации создаются адаптивные и интерактивные веб-приложения.
Попутно реализуем базовые операции создания и удаления пользователей.
Что такое htmx?
Это современное расширение HTML для добавления двунаправленного взаимодействия между браузером и сервером. Кроме создания динамических веб-страниц без единой строчки JavaScript, им прямо в HTML обеспечивается доступ к AJAX, отправляемым сервером событиям и т. д.
Принцип работы htmx
- При взаимодействии пользователя с элементом, в котором имеется атрибут htmx, соответствующее событие, например нажатие кнопки, активируется браузером.
- Событие перехватывается в htmx, и на конечную точку серверной части, указанную в атрибуте, например
hx-get="/my-endpoint", отправляется HTTP-запрос. - В конечной точке серверной части запрос обрабатывается и генерируется HTML-ответ.
- В htmx ответ получается, и DOM обновляется в соответствии с атрибутами
hx-targetиhx-swap. При этом:
— Все содержимое элемента заменяется.
— До или после элемента вставляется новое содержимое.
— Содержимое добавляется в конец элемента.
Проясним на примере:
<button hx-get="/fetch-data" hx-target="#data-container">
Fetch Data
</button>
<div id="data-container"></div>
В этом коде при нажатии кнопки:
- Из htmx в
/fetch-dataотправляется GET-запрос. - В конечной точке серверной части данные извлекаются и отбражаются как HTML.
- Ответ вставляется в элемент
#data-container.
Создание и удаление пользователя
Для создания этого простого приложения понадобятся такие инструменты/фреймворки:
- Gin;
- Tailwind CSS;
- htmx.
Базовая настройка
Создадим в корневом каталоге файл main.go:
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.Run(":8080")
fmt.Println("Server is running on port 8080")
}
Им настраивается базовый сервер Go, запускаемый через порт **8080.
Приложение запускается командойgo run main.go.
- Для отображения списка пользователей создаем в корневом каталоге HTML-файл:
users.html
<!DOCTYPE html>
<html>
<head>
<title>Go + htmx app </title>
<script src="https://unpkg.com/[email protected]" integrity="sha384-wS5l5IKJBvK6sPTKa2WZ1js3d947pvWXbPJ1OmWfEuxLgeHcEbjUUA5i9V5ZkpCw" crossorigin="anonymous"></script>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="text-center flex flex-col w-full gap-6 mt-10">
<table id="user-list" class="w-1/2 mx-auto mt-4 border border-gray-300">
<thead>
<tr class="border border-gray-300">
<th class="px-4 py-2">Name</th>
<th class="px-4 py-2">Email</th>
<th class="px-4 py-2">Actions</th>
</tr>
</thead>
<tbody>
{{ range .users }}
<tr class="border border-gray-300">
<td class="px-4 py-2">{{ .Name }}</td>
<td class="px-4 py-2">{{ .Email }}</td>
<td class="px-4 py-2">
<button class="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-2 rounded">Delete</button>
</td>
</tr>
{{ end }}
</tbody>
</table>
</body>
</html>
Мы включили:
— htmx при помощи тега script;
— Tailwind CSS cdn-ссылкой.
Теперь воспользуемся классами CSS Tailwind и отобразим шаблоны при помощи htmx.
Как видно из users.html, чтобы шаблоном отображался список пользователей, нужно передать в шаблон массив users. Для этого создадим жестко заданный статический список пользователей и маршрут для отображения users.html.
Выборка пользователей
main.go
package main
import (
"fmt"
"net/http"
"text/template"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.GET("/", func(c *gin.Context) {
users := GetUsers()
tmpl := template.Must(template.ParseFiles("users.html"))
err := tmpl.Execute(c.Writer, gin.H{"users": users})
if err != nil {
panic(err)
}
})
router.Run(":8080")
fmt.Println("Server is running on port 8080")
}
type User struct {
Name string
Email string
}
func GetUsers() []User {
return []User{
{Name: "John Doe", Email: "[email protected]"},
{Name: "Alice Smith", Email: "[email protected]"},
}
}
Для отображения списка пользователей добавили маршрут
/и указали статический список, в который потом добавятся новые пользователи.
Вот и все. Перезапускаем сервер и проверяем, отображается ли список пользователей. Такой, например, список:

Создание пользователя
- Создаем файл user_row.html, которым в таблицу user добавляется строка нового пользователя:
user_row.html
<tr class="border border-gray-300">
<td class="px-4 py-2">{{ .Name }}</td>
<td class="px-4 py-2">{{ .Email }}</td>
<td class="px-4 py-2">
<button class="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-2 rounded">Delete</button>
</td>
</tr>
Структура здесь та же, что у строки таблицы user в users.html, так как для новой добавляемой строки нужен такой же стиль.
- Меняем users.html, добавляя над тегами
<table></table>такой код:
<form hx-post="/users" hx-target="#user-list" hx-swap="beforeend">
<input type="text" name="name" placeholder="Name" class="border border-gray-300 p-2 rounded">
<input type="email" name="email" placeholder="Email" class="border border-gray-300 p-2 rounded">
<button type="submit" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Add User</button>
</form>
hx-post=“/users” — когда форма отправится, на маршрут
/usersактивируется post-запрос.
**hx-target=“#user-list” — **указывается цель, куда добавляются данные.
hx-swap=“beforeend” — указывается позиция, куда добавляются данные. Мы добавляем нового пользователя в конец списка, поэтому использовали значение
beforeend.
- Реализуем POST-маршрут
/usersв файле main.go:
router.POST("/users", func(c *gin.Context) {
tmpl := template.Must(template.ParseFiles("user_row.html"))
name := c.PostForm("name")
email := c.PostForm("email")
user := User{Name: name, Email: email}
err := tmpl.Execute(c.Writer, user)
if err != nil {
panic(err)
}
})
Из формы ввода берутся name и email, и user_row.html выполняется.
Попробуем добавить в таблицу нового пользователя. Переходим сюда и нажимаем кнопку Add User:

Читайте также:
- Tailwind CSS: как разработать продвинутую пользовательскую анимацию
- Проекты Go: создаем собственное канареечное развертывание
- Топ-9 PET-проектов для начинающих javascript-разработчиков
Читайте нас в Telegram, VK и Дзен
Перевод статьи Nidhi D: Golang + htmx + Tailwind CSS: Create a Responsive Web Application





