Обновление с версии 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, но считаются устаревшими и, вероятно, будут удалены в какой-то момент в будущем.
-
Замените модификатор слушателя событий
.away
на.outside
<!-- 🚫 До --><div x-show="open" @click.away="open = false">...</div><!-- ✅ После --><div x-show="open" @click.outside="open = false">...</div> -
Используйте
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>