<div x-data="{ count: 0 }"> <button x-on:click="count++"> Увеличить счётчик <span x-text="count"></span> </button></div>
Первые шаги
-
Создайте где-нибудь на компьютере пустой HTML-файл с именем типа
i-love-alpine.html
-
Используя текстовый редактор, заполните файл таким содержимым:
<html><head><script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3/dist/cdn.min.js"></script></head><body><h1 x-data="{ message: 'Я ❤️ Alpine' }" x-text="message"></h1></body></html> -
Откройте свой файл в браузере — если вы увидите
Я ❤️ Alpine
, то можете продолжать!
Теперь, когда всё готово к работе, давайте рассмотрим три практических примера для обучения основам Alpine. К концу этого упражнения вы должны быть более чем готовы к созданию собственных проектов. Продолжим.
Создание счётчика
Давайте начнём с простого компонента «счётчик», чтобы продемонстрировать основы состояния и прослушивания событий в Alpine — двух базовых функций.
Вставьте следующее в тег <body>
:
Теперь вы можете видеть, что с помощью 3 кусочков Alpine, добавленных в этот HTML, мы создали интерактивный компонент «счётчик».
Давайте вкратце рассмотрим происходящее:
Объявление данных
<div x-data="{ count: 0 }"></div>
Всё в Alpine начинается с директивы x-data
. Внутри x-data
на обычном JavaScript объявляется объект данных, который будет отслеживаться Alpine.
Каждое свойство этого объекта будет доступно другим директивам внутри данного HTML-элемента. Кроме того, при изменении одного из этих свойств меняется и всё, что на него опирается.
Давайте посмотрим на x-on
и разберёмся, как он может получить доступ к свойству count
для чтения и изменения:
Прослушивание событий
<button x-on:click="count++">Увеличить счётчик</button>
x-on
— это директива, которую можно использовать для прослушивания любого события на элементе. В данном случае мы слушаем событие click
, поэтому наш вариант выглядит как x-on:click
.
Можно прослушивать и другие события, как вы предполагаете. Например, прослушивание события mouseenter
будет выглядеть следующим образом: x-on:mouseenter
.
Когда происходит событие click
, Alpine вызывает связанное с ним JavaScript-выражение, в нашем случае count++
. Как видите, мы имеем прямой доступ к данным, объявленным в выражении x-data
.
Реагирование на изменения
<span x-text="count"></span>
x-text
— это директива Alpine, которую вы можете использовать для установки текстового содержимого элемента в результат выражения JavaScript.
В данном случае мы указываем Alpine на то, что содержимое тега span
всегда должно отражать значение свойства count
.
Если не понятно, то x-text
, как и большинство директив, принимает в качестве аргумента обычное JavaScript-выражение. Так, например, вместо этого можно задать его содержимое в виде: x-text="count * 2"
и текстовое содержимое span
теперь всегда будет в 2 раза больше значения count
.
Создание спойлера
Теперь, когда мы познакомились с базовой функциональностью, давайте продолжим и рассмотрим важную директиву в Alpine: x-show
, создав компонент «спойлер».
Вставьте в тег <body>
следующий код:
<div x-data="{ open: false }"> <button @click="open = !open">Переключить</button>
<div x-show="open" @click.outside="open = false">Содержимое...</div></div>
Если вы загрузите этот компонент, вы увидите, что «Содержимое…» по умолчанию скрыто. Для отображения скрытого содержимого нужно нажать кнопку «Переключить».
Директивы x-data
и x-on
должны быть знакомы вам по предыдущему примеру, поэтому мы опустим эти пояснения.
Переключение элементов
<div x-show="open" ...>Содержимое...</div>
x-show
— чрезвычайно мощная директива в Alpine, которую можно использовать для отображения и скрытия блока HTML на странице на основе результата выражения JavaScript, в нашем случае: open
.
Прослушивание клика за пределами указанного элемента
<div ... @click.outside="open = false">Содержимое...</div>
В этом примере есть кое-что новое — модификатор .outside
. В Alpine многие директивы поддерживают «модификаторы», которые добавляются через точку в конце директивы.
В данном случае .outside
указывает Alpine реагировать не на клики внутри <div>
, а только если клик произошел снаружи элемента.
Этот встроенный механизм упрощает работу, так как такая задача встречается часто, а реализовать её вручную довольно неудобно.
Создание поля поиска
Теперь построим более сложный компонент и введём несколько других директив и паттернов.
Вставьте в тег <body>
следующий код:
<div x-data="{ search: '', items: ['foo', 'bar', 'baz'], get filteredItems() { return this.items.filter( i => i.startsWith(this.search) ) } }"> <input x-model="search" placeholder="Поиск..."> <ul> <template x-for="item in filteredItems" :key="item"> <li x-text="item"></li> </template> </ul></div>
По умолчанию все «элементы» (foo, bar и baz) будут отображаться на странице, но вы можете отфильтровать их, введя текст в поле ввода. По мере ввода список элементов будет меняться в зависимости от того, что вы ищете.
Здесь происходит немало событий, поэтому давайте пройдёмся по этому фрагменту по частям.
Многострочное форматирование
Первое, на что хотелось бы обратить внимание, это то, что в x-data
теперь происходит гораздо больше событий, чем раньше. Для удобства написания и чтения мы разбили его на несколько строк в нашем HTML. Это совершенно необязательно, и мы ещё поговорим о том, как избежать этой проблемы, а пока оставим весь этот JavaScript непосредственно в HTML.
Привязка к полям
<input x-model="search" placeholder="Поиск..." />
Вы заметите новую директиву, с которой мы ещё не встречались: x-model
.
x-model
используется для «привязки» значения входного элемента к свойству данных: в нашем случае «search» из x-data="{ search: '', ... }"
.
Это означает, что каждый раз, когда значение ввода изменяется, значение «поиск» будет меняться, чтобы отразить это.
x-model
способна на гораздо большее, чем этот простой пример.
Вычисляемые свойства с использованием геттеров
Следующий момент, на который я хотел бы обратить ваше внимание — это свойства items
и filteredItems
из директивы x-data
.
{ ... items: ['foo', 'bar', 'baz'],
get filteredItems() { return this.items.filter( i => i.startsWith(this.search) ) }}
Свойство items
не требует пояснений. Здесь мы устанавливаем значение items
в массив JavaScript, состоящий из 3 различных элементов (foo, bar и baz).
Интересной частью этого фрагмента является свойство filteredItems
.
Обозначаемый префиксом get
для этого свойства, filteredItems
является «getter»-свойством в этом объекте. Это означает, что мы можем получить доступ к фильтруемым элементам, как если бы это было обычное свойство нашего объекта данных, но когда мы это сделаем, JavaScript выполнит запуск предоставленной функции и вернёт результат.
Вполне приемлемо отказаться от get
и просто сделать его методом, который можно вызывать из шаблона, но некоторые предпочитают более удобный синтаксис геттера.
Теперь заглянем в геттер filteredItems
и убедимся, что мы понимаем, что там происходит:
return this.items.filter((i) => i.startsWith(this.search));
Это всё простой JavaScript. Сначала мы получаем массив элементов (foo, bar и baz) и фильтруем их, используя предоставленный обратный вызов: i => i.startsWith(this.search)
.
Передавая этот обратный вызов в filter
, мы говорим JavaScript, чтобы он возвращал только те элементы, которые начинаются со строки: this.search
, которая, как мы видели с x-model
, всегда будет отражать значение поля ввода.
Вы можете заметить, что до сих пор нам не приходилось использовать this
для ссылки на свойства. Однако, поскольку мы работаем непосредственно внутри объекта x-data
, мы должны ссылаться на любые свойства, используя this.[property]
вместо [property]
.
Потому что Alpine — это «реактивный» фреймворк. При каждом изменении значения this.search
части шаблона, использующие filteredItems
, будут автоматически обновляться.
Повторение элементов
Теперь, когда мы разобрались с внутренней частью нашего компонента, давайте поймем, что происходит в шаблоне, который позволяет нам перебирать filteredItems
на странице.
<ul> <template x-for="item in filteredItems"> <li x-text="item"></li> </template></ul>
Первое, на что следует обратить внимание, — это директива x-for
. Выражения x-for
имеют следующий вид: [item] in [items]
, где [items]
— произвольный массив данных, а [item]
— имя переменной, которой будет присвоена итерация внутри цикла.
Также обратите внимание, что x-for
объявляется на элементе <template>
, а не непосредственно на <li>
. Это является обязательным условием использования x-for
. Это позволяет Alpine использовать существующее поведение тегов <template>
в браузере в своих интересах.
Теперь любой элемент внутри тега <template>
будет повторяться для каждого элемента внутри filteredItems
, а все выражения, вычисляемые внутри цикла, будут иметь прямой доступ к итерационной переменной (в данном случае item
).
Проверка знаний
-
Самая важная директива в Alpine.js…
-
Нажатие на какую из кнопок приведёт к переключению спойлера?
<div x-data="{ open: false }">// код кнопки<div x-show="open" @click.outside="open = false">Содержимое...</div></div> -
Синтаксис геттеров внутри объекта
x-data
выглядит как…
Итоги
Если вы дошли до этого момента, значит, в Alpine вы познакомились со следующими директивами:
- x-data
- x-on
- x-text
- x-show
- x-model
- x-for
Это отличное начало, однако есть ещё много нюансов, в которые стоит вникнуть. Лучший способ освоить Alpine — прочитать эту документацию. Не нужно прочёсывать каждое слово, но если вы хотя бы просмотрите каждую страницу, то будете НАМНОГО эффективнее использовать Alpine.
Приятного кодирования!