x-ref и $refs
Обычно Alpine меняет страницу сам, по данным. Но иногда нужен сам элемент: поставить курсор в поле, прокрутить список, измерить размер. Директива x-ref даёт элементу имя, а объект $refs возвращает элемент по этому имени — без querySelector.
Имя и обращение
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data>
<input x-ref="title" placeholder="Новая задача">
<button @click="$refs.title.focus()">Перейти к полю</button>
</div>Клик по кнопке ставит курсор в поле ввода. $refs.title — обычный DOM-элемент, у него есть все методы из уроков о работе со страницей.
Фокус после добавления
В списке дел удобно возвращать курсор в поле после добавления задачи, чтобы сразу вводить следующую:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data="{
title: '',
tasks: [],
add() {
if (this.title === '') return;
this.tasks.push(this.title);
this.title = '';
this.$refs.title.focus();
}
}">
<input x-ref="title" x-model="title" @keydown.enter="add()" placeholder="Новая задача">
<button @click="add()">Добавить</button>
<p x-text="tasks.join(', ')"></p>
</div>Нажмите кнопку мышью — задача добавится, а курсор вернётся в поле. Внутри методов $refs доступен через this, как и данные.
Прокрутка списка
Ещё один частый случай — прокрутить контейнер к последнему элементу:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data="{ tasks: ['Задача 1', 'Задача 2', 'Задача 3'] }">
<ul x-ref="list" style="height: 80px; overflow: auto; border: 1px solid #ccc">
<template x-for="task in tasks">
<li x-text="task"></li>
</template>
</ul>
<button @click="tasks.push('Задача ' + (tasks.length + 1)); $nextTick(() => $refs.list.scrollTop = $refs.list.scrollHeight)">
Добавить
</button>
</div>Каждая новая задача добавляется внизу, и список прокручивается к ней. $nextTick ждёт, пока Alpine добавит пункт на страницу, — подробнее о нём в уроке о магических свойствах.
Когда $refs не нужен
Если задачу можно решить данными, решайте данными. Прочитать текст поля — это x-model, а не $refs.title.value. Спрятать элемент — x-show, а не $refs.box.style.display. $refs оставляют для действий, которых нет в данных: фокус, прокрутка, размеры, вызов методов сторонних библиотек.
Частая ошибка
Обращаться к x-ref из соседнего компонента. $refs видит элементы своего компонента и тех, внутри которых он лежит, но не компонентов рядом. Если кнопка и поле стоят в двух соседних элементах с x-data, $refs.title будет undefined и вызов focus() закончится ошибкой. Объедините их в один компонент или передайте сигнал событием через $dispatch.