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

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

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

Play

Обновление с 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, теперь вам нужно будет вручную вызывать Alpine.start() для v3. Это не повлияет на вас, если вы используете файл сборки 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>