Перейти к содержимому

Обновление с версии v2

Ниже приведено исчерпывающее руководство по основным изменениям в Alpine v3, но если вы предпочитаете что-то более интересное, вы можете просмотреть все изменения, а также новые функции в v3, посмотрев доклад Alpine Day 2021 «Будущее Alpine»:

Обновление с Alpine v2 до v3 должно пройти довольно безболезненно. Во многих случаях НИЧЕГО не нужно делать с вашей кодовой базой, чтобы использовать v3. Ниже приведён список критических изменений в порядке убывания вероятности того, что они повлияют на пользователей:

Критические изменения

$el теперь указывает на целевой элемент

$el всегда ссылается на элемент, над которым выполнено выражение, а не на корневой элемент компонента. Это уменьшает необходимость использования x-ref. Если же вам всё-таки нужно получить доступ к корневому элементу компонента, используйте $root. Например:

<!-- 🚫 До -->
<div x-data>
<button @click="console.log($el)"></button>
<!-- В v2 $el был <div>, теперь это <button>. -->
</div>
<!-- ✅ После -->
<div x-data>
<button @click="console.log($root)"></button>
</div>

Для более плавного обновления можно заменить все экземпляры $el на пользовательскую магию $root.

Автоматическое выполнение функций init(), определённых в объекте data

Распространённой схемой в v2 был ручной вызов метода init() (или аналогичного по названию метода) для объекта x-data.

В v3 Alpine будет автоматически вызывать методы init() у объектов данных.

<!-- 🚫 До -->
<div x-data="foo()" x-init="init()"></div>
<!-- ✅ После -->
<div x-data="foo()"></div>
<script>
function foo() {
return {
init() {
//
},
};
}
</script>

Вызывайте Alpine.start() после импорта

Если вы импортировали Alpine v2 через NPM, теперь для работы с v3 вам нужно будет вручную вызывать Alpine.start(). Это не затронет пользователей, которые используют файл сборки Alpine или CDN через тег <template>.

// 🚫 До
import 'alpinejs';
// ✅ После
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();

Вместо x-show.transition теперь используется x-transition

Все возможности, которые предоставляли хелперы x-show.transition..., остаются доступными, но теперь через более унифицированный API — x-transition.

<!-- 🚫 До -->
<div x-show.transition="open"></div>
<!-- ✅ После -->
<div x-show="open" x-transition></div>
<!-- 🚫 До -->
<div x-show.transition.duration.500ms="open"></div>
<!-- ✅ После -->
<div x-show="open" x-transition.duration.500ms></div>
<!-- 🚫 До -->
<div x-show.transition.in.duration.500ms.out.duration.750ms="open"></div>
<!-- ✅ После -->
<div x-show="open" x-transition:enter.duration.500ms x-transition:leave.duration.750ms></div>

x-if больше не поддерживает x-transition

Возможность перемещать элементы и добавлять их до/после удаления из DOM больше не доступна в Alpine.

Это была функция, о существовании которой даже мало кто знал, не говоря уже об использовании.

Поскольку система переходов сложна, с точки зрения обслуживания имеет смысл поддерживать переходные элементы только с помощью x-show.

<!-- 🚫 До -->
<template x-if.transition="open">
<div>...</div>
</template>
<!-- ✅ После -->
<div x-show="open" x-transition>...</div>

x-data имеет каскадную область видимости

Область, определённая в x-data, теперь доступна всем дочерним элементам, если она не перезаписана вложенным выражением x-data.

<!-- 🚫 До -->
<div x-data="{ foo: 'bar' }">
<div x-data="{}">
<!-- foo не определено -->
</div>
</div>
<!-- ✅ После -->
<div x-data="{ foo: 'bar' }">
<div x-data="{}">
<!-- foo равно 'bar' -->
</div>
</div>

x-init больше не принимает функцию обратного вызова

До v3, если x-init получал возвращаемое значение, являющееся «функцией» typeof, он выполнял обратный вызов после того, как Alpine завершала инициализацию всех остальных директив в дереве. Теперь вам нужно вручную вызывать $nextTick(), чтобы добиться такого поведения. x-init больше не «распознает возвращаемое значение».

<!-- 🚫 До -->
<div x-data x-init="() => { ... }">...</div>
<!-- ✅ После -->
<div x-data x-init="$nextTick(() => { ... })">...</div>

Возврат false из обработчиков событий больше не приводит к неявному preventDefault

Alpine v2 воспринимает возвращаемое значение false как желание запустить preventDefault для события. Это соответствует стандартному поведению встроенных слушателей: <... oninput="someFunctionThatReturnsFalse()">. Alpine v3 больше не поддерживает этот API. Большинство людей не знают о его существовании, и поэтому поведение является удивительным.

<!-- 🚫 До -->
<div x-data="{ blockInput() { return false } }">
<input type="text" @input="blockInput()" />
</div>
<!-- ✅ После -->
<div x-data="{ blockInput(e) { e.preventDefault() } }">
<input type="text" @input="blockInput($event)" />
</div>

Вместо x-spread теперь используется x-bind

Одна из историй повторного использования функциональности в Alpine — абстрагирование директив Alpine в объекты и применение их к элементам с помощью x-spread. Это поведение осталось прежним, за исключением того, что теперь вместо x-spread нужно использовать x-bind.

<!-- 🚫 До -->
<div x-data="dropdown()">
<button x-spread="trigger">Переключить</button>
<div x-spread="dialogue">...</div>
</div>
<!-- ✅ После -->
<div x-data="dropdown()">
<button x-bind="trigger">Переключить</button>
<div x-bind="dialogue">...</div>
</div>
<script>
function dropdown() {
return {
open: false,
trigger: {
'x-on:click'() {
this.open = !this.open;
},
},
dialogue: {
'x-show'() {
return this.open;
},
'x-bind:class'() {
return 'foo bar';
},
},
};
}
</script>

Использование глобальных событий жизненного цикла вместо Alpine.deferLoadingAlpine()

<!-- 🚫 До -->
<script>
window.deferLoadingAlpine = (startAlpine) => {
// Будет выполнено перед инициализацией Alpine.
startAlpine();
// Будет выполнено после инициализации Alpine.
};
</script>
<!-- ✅ После -->
<script>
document.addEventListener('alpine:init', () => {
// Будет выполнено перед инициализацией Alpine.
});
document.addEventListener('alpine:initialized', () => {
// Будет выполнено после инициализации Alpine.
});
</script>

x-ref больше не поддерживает связывание

В Alpine v2 для кода ниже

<div x-data="{options: [{value: 1}, {value: 2}, {value: 3}] }">
<div x-ref="0">0</div>
<template x-for="option in options">
<div :x-ref="option.value" x-text="option.value"></div>
</template>
<button @click="console.log($refs[0], $refs[1], $refs[2], $refs[3]);">Отобразить $refs</button>
</div>

после нажатия кнопки отображались все $refs. Однако в Alpine v3 возможен доступ только к $refs для элементов, созданных статически, поэтому, как и ожидалось, будет возвращена только первая ссылка.

Поддержка IE11 прекращена

Alpine больше не поддерживает Internet Explorer 11. Если вам нужна поддержка IE11, продолжайте использовать Alpine v2.

Устаревшие API

Следующие два API по-прежнему будут работать в версии 3, но считаются устаревшими и, вероятно, будут удалены в какой-то момент в будущем.

  1. Замените модификатор слушателя событий .away на .outside

    <!-- 🚫 До -->
    <div x-show="open" @click.away="open = false">...</div>
    <!-- ✅ После -->
    <div x-show="open" @click.outside="open = false">...</div>
  2. Используйте Alpine.data() вместо глобальных функций

    <!-- 🚫 До -->
    <div x-data="dropdown()">...</div>
    <script>
    function dropdown() {
    return {
    ...
    }
    }
    </script>
    <!-- ✅ После -->
    <div x-data="dropdown">...</div>
    <script>
    document.addEventListener('alpine:init', () => {
    Alpine.data('dropdown', () => ({
    ...
    }))
    })
    </script>