Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Компоненты через 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().

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.