Компоненты через Alpine.data
Когда объект в x-data разрастается до десятка строк, разметку становится трудно читать. Alpine.data() регистрирует компонент под именем: данные и методы живут в JavaScript, а в HTML остаётся короткое x-data="todos". Один и тот же компонент можно поставить на страницу несколько раз.
Регистрация при подключении через CDN
Компонент нужно зарегистрировать до того, как Alpine начнёт обходить страницу. Для этого есть событие alpine:init — Alpine отправляет его перед запуском. Код размещают в обычном теге <script> в index.html:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('todos', () => ({
title: '',
tasks: [],
add() {
if (this.title === '') return;
this.tasks.push(this.title);
this.title = '';
}
}));
});
</script>
<div x-data="todos">
<input x-model="title" @keydown.enter="add()" placeholder="Новая задача">
<ul>
<template x-for="task in tasks">
<li x-text="task"></li>
</template>
</ul>
</div>Работает так же, как раньше, но разметка короче. Вторым аргументом Alpine.data() передают функцию, которая возвращает объект, — каждый компонент получает свою копию данных.
Параметры
Функция может принимать аргументы. Их передают в x-data как при вызове:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('todos', (initial = []) => ({
tasks: initial,
get count() {
return this.tasks.length;
}
}));
});
</script>
<div x-data="todos(['Купить молоко', 'Позвонить Олегу'])">
<p x-text="'Дома: ' + count"></p>
</div>
<div x-data="todos(['Отчёт'])">
<p x-text="'Работа: ' + count"></p>
</div>На странице два независимых списка: «Дома: 2» и «Работа: 1».
Регистрация в проекте с npm
В проекте Vite компонент удобно держать в отдельном модуле. Создайте файл src/todos.js:
// src/todos.js
export default (initial = []) => ({
title: '',
tasks: initial,
add() {
if (this.title === '') return;
this.tasks.push(this.title);
this.title = '';
}
});Зарегистрируйте его в src/main.js до вызова Alpine.start():
// src/main.js
import Alpine from 'alpinejs';
import todos from './todos.js';
Alpine.data('todos', todos);
window.Alpine = Alpine;
Alpine.start();В index.html компонент используется так же: x-data="todos".
Частая ошибка
Зарегистрировать компонент позже, чем запустился Alpine: в src/main.js после Alpine.start() или при CDN без обработчика alpine:init, например в DOMContentLoaded. Alpine уже обошёл страницу, не нашёл todos и вывел в консоль ошибку todos is not defined. Регистрируйте компоненты внутри alpine:init или до Alpine.start().