Организация циклов в Alpine.js
03-12-2020Время чтения ~ 4 мин.Alpine.js 7298
Циклы используются там, где нужно повторить какой-то html-вывод по единому шаблону. Я уже показывал пример использования при выводе данных, полученных по Ajax.
То есть первый вид цикла — это обход готового массива данных. Второй вариант — это цикл с заданным количеством итераций.
В Alpine.js для организации циклов используется директива x-for. Как и x-if она может применяться только к тэгу TEMPLATE и иметь один корневой элемент.
Заданное количество итераций
В обычной практики такие задачи достаточно редки, поэтому я придумал пример по выводу css-класса цвета Berry CSS.
<div x-data>
<div class="b-flex flex-wrap">
<template x-for="i in 9">
<div :class="'bg-blue'+ i + '00'" :title="'blue' + i + '00'" class="pad20"></div>
</template>
</div>
</div>
Это достаточно простой пример, где в цикле используется переменная i — счётчик. Мы её используем, чтобы сформировать имя класса и всплывающую подсказку.
Обычно такие циклы делаются на JS или PHP, а тут вся магия на уровне HTML.
Этот пример можно усложнить.
<div x-data>
<div class="b-flex flex-wrap">
<template x-for="i in 9">
<div :class="{
'bg-blue100 t-blue500': i == 1,
'bg-blue200 t-blue600': i == 2,
'bg-blue300 t-blue700': i == 3,
'bg-blue400 t-blue800': i == 4,
'bg-blue500 t-white': i == 5,
'bg-blue600 t-blue50': i == 6,
'bg-blue700 t-blue100': i == 7,
'bg-blue800 t-blue200': i == 8,
'bg-blue900 t-blue300': i == 9,
}" x-text="'blue' + i + '00'" class="pad10 t90"></div>
</template>
</div>
</div>
Смысл тот же, только больше логики для каждой итерации.
Обратите внимание, что данный цикл начинается с единицы, а не с нуля.
Обход данных в цикле
Суть такого цикла в том, чтобы отделить данные от их представления. Например табличный вывод однотипных данных, где удобней задать данные каждой строки в виде массива, а вывод уже сделать по шаблону.
Например такой вариант.
<div x-data='{users: [
{id: 1, name: "Leanne Graham", email: "Sincere@april.biz"},
{id: 2, name: "Ervin Howell", email: "Shanna@melissa.tv"},
{id: 3, name: "Clementine Bauch", email: "Nathan@yesenia.net"}
]}'>
<template x-for="user in users" :key="user.id">
<div class="b-flex">
<div x-text="user.name" class="w3col"></div>
<div x-text="user.email"></div>
</div>
</template>
</div>
Здесь в переменной users хранится массив данных по каждому пользователю. Ключ :key для цикла может не использоваться, но рекомендуется для улучшения работы Alpine.
При желании данные можно разместить в отдельной функции и подключить её в x-data.Преобразование PHP-массива в JSON для JS
Намного интереснее вариант, когда данные получаются через PHP. Это может быть запрос к базе данных, а может и файл, который возвращает результат по return. В любом случае эти данные нужно как-то преобразовать в JS-код, а точнее в JSON-формат.
На самом деле — это просто, поскольку в PHP уже есть готовая функция json_encode().
<?php
$users = [
[
'id' => 1,
'name' => 'Leanne Graham',
'email' => 'Sincere@april.biz',
],
[
'id' => 2,
'name' => 'Ervin Howell',
'email' => 'Shanna@melissa.tv',
],
[
'id' => 3,
'name' => 'Clementine Bauch',
'email' => 'Nathan@yesenia.net',
],
];
$jsonData = json_encode($users, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK);
?>
<div x-data='{users: <?= $jsonData ?>}'>
<template x-for="user in users" :key="user.id">
<div class="b-flex">
<div x-text="user.name" class="w3col"></div>
<div x-text="user.email"></div>
</div>
</template>
</div>
Нюанс в том, что функцию json_encode() нужно использовать с параметрами JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK. Тогда она вернёт нормальные данные для JavaScript.
Доступ к счетчику текущей итерации цикла
Обратите внимание, что в данных есть уникальный id — это вроде как «номер по списку». Во многих случаях он не нужен, поскольку данные можно нумеровать последовательно с первого по последний. Для таких случаев предусмотрен дополнительный синтаксис x-for.
<div x-data='{users: [
{name: "Leanne Graham", email: "Sincere@april.biz"},
{name: "Ervin Howell", email: "Shanna@melissa.tv"},
{name: "Clementine Bauch", email: "Nathan@yesenia.net"}
]}'>
<template x-for="(user, index) in users" :key="user.name">
<div class="b-flex">
<div x-text="index + 1 + '.'" class="mar5-r"></div>
<div x-text="user.name" class="w3col"></div>
<div x-text="user.email"></div>
</div>
</template>
</div>
В данных я убрал поле id, а в цикле добавил переменную для счетчика index. В шаблоне мы просто его выводим как и другие переменные.
Нумерация такого счетчика с нуля, поэтому я прибавляю 1 и добавляю точку для красоты.
Также счётчики можно вкладывать друг в друга. Это нужно, когда данные представляют собой многомерный массив массивов, но я уже с трудом представлю себе такие задачи на практике. :-)