Alpine.js - лёгкая альтернатива jQuery
24-11-2020Reading time ~ 6 min.Alpine.js 9758
Я давно уже присматриваюсь к Alpine.js, поскольку этот js-фреймворк выделяется из ряда других. По своей сути он очень близок к Vue.js, но при этом может работать как привычный jQuery.
Основной массе разработчиков просто не нужны все те «фишки», что предлагают React или Vue. Вообще работа с JavaScript всегда происходит по одному алгоритму — вначале получили элемент/элементы на странице, после делаем с ними какие-то манипуляции.
Точно также работает и система событий — прописали либо onclick к нужному html-элементу, либо навесили событие через «слушатель» addEventListener и дальше через js-функцию делаем что нужно. Поскольку JavaScript очень уж многословен, а во многих случаях и неочевиден, то и возникли библиотеки функций — jQuery как раз одна из них. С их помощью работать с js намного приятней.
Но современные js-фреймворки помимо своих функций, предлагают немного другой подход, основанный на синтаксическом «сахаре» — который не имеет никакого смысла вне используемого фреймворка. Такой синтаксис наверное даже удобней функций jQuery (и других аналогов).
За это приходится расплачиваться. Основное ограничение — такие фреймворки требуют для своей работы Node.js, поскольку исходный код нужно скомпилировать в полноценный JavaScript, который уже будет понимать браузер. Да, формально можно использовать готовые сборки того же React или Vue, но размер их js-файлов достаточно большой: 120 и 93Кб. Даже jQuery 3.5 весит меньше — 89Кб. Если мы хотим сэкономить на загрузке (а js-код критично важен для браузера), то нет смысла использовать тот же Vue. И это при том, что в таком варианте мы лишаемся всех «плюшек» синтаксического «сахара».
Использование Node.js тоже не имеет смысла, если нам нужно сделать какие-то простые вещи, вроде сменить css-класс или отследить click на кнопке. Ставить ради этого гигантский Node.js неразумно.
Alpine.js выделяется тем, что имеет очень небольшие размеры (всего 25Кб), не требует компиляции, но при этом поддерживает синтаксический «сахар» как и «большие» фреймворки.
Важно то, что Alpine.js можно загружать в конце BODY, что даёт прирост скорости страницы. Если jQuery (и аналоги) мы вынуждены загружать в секцию HEAD (поскольку в теле страницы произвольно могут встретиться её функции), то с Alpine.js мы вообще не задумываемся об этом. Достаточно прописать загрузку как обычный js-файл:
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js"></script>
После этого на странице можно использовать возможности Alpine.
Здесь я хочу обратить внимание на то, что есть существенное отличие от того, как мы привыкли работать с jQuery или даже нативным JS.
Например нам нужно отследить обычный click на каком-то элементе. Обычно мы прописываем css-класс или уникальный id и потом цепляемся к нему с помощью события onclick, в котором прописываем функцию-обработчик.
В Alpine схема заимствованна из «больших» фреймворков (в основном — из Vue), где применяется компонентный подход. В нём мы объявляем, что какой-то элемент, например DIV будет являться компонентом, или в современных терминах — ему добавляется «реактивность». Такой компонент будет представлять собой единую сущность: со своими данным и поведением.
<div x-data> содержимое </div>
Директива x-data
— это та самая инструкция, которая указывает Alpine добавить реактивности в данный блок. Всё, что окажется внутри — и будет представлять собой единый компонент.
В Alpine всего 14 директив и все они начинаются с префикса x-
. Основная x-data
не только указывает на сам компонент, но и позволяет сразу инициализировать данные.
<div x-data="{t: false}"> содержимое </div>
В данном примере будет создана переменная t
со значением false
. Поскольку это обычный js-объект, то в нём можно определить любые данные (или функцию, которая их вернёт).
Теперь сделаем простой пример, в котором будет отслеживать событие onclick
при котором менять css-класс (аля-toggle).
<div x-data="{t: false}"> <div x-on:click="t = !t" x-bind:class="{ 't-red': t }">Toggle class click</div> </div>
В x-data
мы создаём переменную, которая будет хранить текущее состояние элемента. Директива x-on:click
отслеживает событие onclick
, где в кавычках указывается js-код — как будто-бы это обычная js-функция. В данном случае мы инвертируем значение t
.
Дальше мы используем директиву x-bind
, которая связывает атрибут тэга (здесь это class) с логическими выражениями. Конкретно в этом примере css-класс t-red
добавится к этому элементу только, если t
будет истинно (true).
Мы кликаем на элементе, меняется переменная t
, которая влияет на bind-связку и css-класс автоматом добавляется. Второй клик инвертирует t
и класс удаляется.
Этот же самый пример можно оформить ещё проще:
<div x-data="{t: false}"> <div @click="t = !t" :class="{ 't-red': t }">Toogle class click</div> </div>
То есть @
заменяется на x-on:
, а :
на x-bind:
.
Можно не создавать оборачивающий блок, если это одиночный элемент:
<div x-data="{t: false}" @click="t = !t" :class="{'t-red': t}">Toogle class click</div>
Похожий пример, только отслеживаем событие аля-hover:
<div x-data="{t: false}"> <div @mouseover="t = true" @mouseout="t = false" :class="{'t-red': t}">Toogle class hover</div> </div>
Эти примеры очень похожи на то с чем мы постоянно сталкиваемся в jQuery: поменять css-класс при каком-то событии.
Рассмотрим ещё пару примеров. Этот мне особенно нравится:
<div x-data="{ open: false }" class="pos-relative b-inline"> <button @click="open = true" class="button button1">Open</button> <div x-show="open" @click.away="open = false" class="animation-fade pad20 bordered pos-absolute w200px z-index1 bg-white" x-cloak> Content </div> </div>
Это обычный dropdown, который раскрывает блок контента по клику. Я использую классы Berry CSS, которые семантически понятны.
Здесь мы определяем переменную open
, которая хранит состояние блока контента (скрыт/открыт). У блока контента используется директива x-show
, которая содержит js-выражение. Если это false, то x-show
скроет блок через display: none
. Таким образом, кликнув на кнопку мы открываем блок контента через переменную open
.
У контента есть ещё одна директива @click.away
, которая указывает на клик, но вне этого блока. Именно поэтому, когда мы повторно кликаем на кнопку или любую другую часть страницы, переменная open
становится false
и блок скрывается.
Директива x-cloak
, а точнее это атрибут тэга, особенная. Её назначение в том, чтобы исчезнуть как только Alpine будет проинициализирован. Смысл в том, что js-файл Alpine может загружаться дольше, чем браузер начнёт отображать страницу, а значит блоки, который по умолчанию должны быть скрыты — будут изначально показаны. И как только сработает Alpine они уже отобразятся как задумано. Вот эта задержка может приводить к неприятному «мельканию». Поэтому для таких блоков достаточно указать x-cloak
, а в css-стилях прописать:
<style> [x-cloak] {display: none;} </style>
Пока Alpine не загружена, блок будет скрыт. При этом нам не нужно что-либо ещё отслеживать.
Пример с dropdown может использовать и для меню, и для модальных окон. Мы по сути не написали ни строчки js-кода, а получили потрясающую функциональность. Это не сравнится ни с jQuery, ни с нативным JS.
Ну и последний пример — табы.
<div x-data="{ tab: 'foo' }"> <button :class="{ 'bg-blue': tab === 'foo' }" @click="tab = 'foo'">Foo</button> <button :class="{ 'bg-blue': tab === 'bar' }" @click="tab = 'bar'">Bar</button> <div class="pad20 bordered"> <div x-show="tab === 'foo'" class="animation-fade">Вкладка Foo</div> <div x-show="tab === 'bar'" class="animation-fade" x-cloak>Вкладка Bar</div> </div> </div>
Если вы когда-нибудь делали свои табы, то поймёте насколько компактным и универсальным получился этот код. Мне кажется, что более простой реализации и не существует...
Что в итоге? Для меня Alpine.js — настоящая находка, которая доказывает, что использовать js-интерактивность в html-коде можно просто и удобно. При этом возможности Alpine намного больше — многие из них рассчитаны на опытных js-разработчиков. Но и для обычных вебмастеров, которым нужно решать простые задачи, Alpine.js может пригодится как лёгкая замена jQuery.
Круто, а с ajax он как-то работает?
Ну конечно. Ajax реализуется через обычные js-функции. Можно их навесить на события Alpine, как обычно.
Код не сохранился:
Может будет полезно: заготовка для пошаговой формы.