AlpineJS – jQuery здорової людини
Зміст
Бібліотека jQuery давно втратила популярність серед розробників, вони не використовують її для нових проєктів і на це є багато причин. Звісно в легасі інтернеті jQuery є і буде, але що тоді робити з новими сторінками? Є альтернатива! І тут я вам трохи розповім про AlpineJS і на що ця бібліотека здатна. Разом з демо і прикладами коду.
AlpineJS. Проста. Легка. Заряджена до зубів.⌗
Хоч розробники і називають AlpineJS фреймворком, я ж буду свідомо використовувати “бібліотека”, щоб не відлякувати потенційних користувачів. За спиною у бібліотеки стоїть дуже проста ідея, дати можливість вписати мінімум скомпонованого коду прямо у розмітку HTML, щоб додати сторінкам динаміки не використовуючи такі бібліотеки як React, чи Solid заради форми на лендінг сторінці.
Загалом AlpineJS налічує 15 атрибутів, 6 властивостей та два методи, чого вистачає для будь яких потреб пересічної сторінки, а головне це все важить ~15кб, а якщо ви читали мої дописи, то знаєте, що для найкращого досвіду користування сайтом сторінка повинна важити менше 14кб.
А сайт бібліотеки каже, щоб ми думали про неї, як про jQuery для сучасного вебу і хто ми такі, щоб цьому перечити ;)
Що можна написати з AlpineJS на прикладі з поясненнями⌗
Хотілось показати вам щось просте для розуміння, але в той же час щось що буде використовувати по максимуму типовий функціонал, яки є на кожному сайті. Презентую вам форму з випадковими картинками.
Це звичайний script
тег, який розміщується в head
сторінки. Так само цей код можна лишити прямо у HTML, або винести в окремий модуль, за потреби.
<script>
async function fetchRandomPicUrl(size) {
const res = await fetch(
"https://random.imagecdn.app/v1/image?width=" + size + "&height=" + size
);
const url = await res.text();
return url;
}
</script>
Безпосередньо сама розмітка, яка включає в себе динамічний функціонал за допомоги AlpineJS. Далі по порядку про кожен використаний елемент з бібліотеки.
<div
x-data="{ url: null, size: 500 }"
x-init="url = await fetchRandomPicUrl(size)"
class="flex-center"
>
<template x-if="url == null">
<div class="flex-center image-placeholder">Завантажую...</div>
</template>
<template x-if="url">
<div class="flex-center">
<div class="header">
<label>
Розмір зображення:
<input required min="100" max="1000" type="number" x-model="size" />
</label>
<button
@click="url = await fetchRandomPicUrl(size)"
:disabled="size < 100 || size > 1000 ? true : false"
>
Застосувати
</button>
</div>
<figure>
<img x-bind:src="url" alt="random picture" />
<figcaption class="flex-center">
<button @click="url = await fetchRandomPicUrl(size)">
Нове зображення
</button>
</figcaption>
</figure>
</div>
</template>
</div>
x-data⌗
По суті x-data
описує компонент в AlpineJS і створює набір початкових даних – стан (state), до яких можна отримати доступ всередині компонента і всім дочірнім компонентам.
x-init⌗
Хук, який дозволяє виконати якусь функцію, до того, як бібліотека продовжить маніпуляції з DOM-деревом
В моєму випадку я викликаю функцію зі свого script
тегу, передаючи аргумент який у мене зберігається на даний момент у size
. Тобто, як ми бачимо данні з x-data
доступні у компоненті просто по ключу без додаткового синтаксису. Також функції мають верхньорівневий await
, що дозволяє дочекатись результату і просто за допомогою =
записати так само в url
і оновити тим самим x-data
.
x-init="url = await fetchRandomPicUrl(size)"
x-if⌗
Тут все доволі просто. По суті це вбудований синтаксичний цукор до css властивості display: none;
, яка має ті самі недоліки, як неможливість застосувати анімацію переходу (transition).
Важливо
Оскільки x-if
вирізає елемент з DOM-дерева, його необхідно огорнути у тег template
і вже в ньому використовувати сам атрибут.
x-model⌗
Це двостороння привʼязка даних, як в vue
, svelte
чи angular
, але якщо ви з react
чи solid
, то по суті x-model
замінює value
та onChange
. Тобто ваше значення інпута і данні в стані будуть завжди синхронізовані і впливати один на одного.
Тобто коли ми пишемо щось в input
данні в x-state
змінюються і якщо ми оновимо самі данні програмно в x-state
вони поміняються одразу в нашому input
.
<input required min="100" max="1000" type="number" x-model="size" />
x-on або @⌗
x-on
або скорочення @
дозволяє створити listener для подій. У нашому прикладі я використовую скорочення @
яке розробники бібліотеки зробили через часту вживаність цього атрибуту щоб слухати клік кнопки і виконувати новий запит на сервер ідентичний тому, що я описав в x-init
Важливо
Умовний listener x-on:click
=== @click
x-bind aбо :⌗
Так само, як і попередній атрибут x-bind
має скорочення – :
. Цей атрибут використовується, для додавання до HTML елементів інших атрибутів, таких як class
, style
, src
або disabled
. У моєму прикладі саме останній, який за допомогою простої умови блокує кнопку, якщо значення розміру зображення завелике, чи замале.
:disabled="size < 100 || size > 1000 ? true : false"
Також далі по коду я використовую вже повну версію x-bind:src
для того, щоб записувати одразу посилання на зображення, яке приходить з серверу.
<img x-bind:src="url" alt="random picture" />
Короткий висновок і пара думок⌗
Як видно з коду всього за допомогою декількох символів і коротких слів, ми можемо оживити сторінку і додати дуже багато типового функціоналу. Навіть в такому маленькому прикладі ми бачимо і роботу з формами і з DOM-деревом, до того ж покривається одразу декілька різних задач, як оновлення, або умовне відображення. Документація має ще більше цікавинок, таких як store, система плагінів і інші цікавинки.
Моя думка, що AlpineJS підійде для лендінгів, або інших сайтів, де основний контент статичний, але треба мати змогу додати трохи точкової динаміки. Наприклад, якщо ви робите міні-магазин, то зверставши унікальні сторінки для 5 продуктів і написавши корзину на AlpineJS це, буде одне з найкращих рішень в плані швидкості, оптимізації та задоволення від роботи.