
Содержание статьи
автор Хасан Джирде

Воспроизведение списка является одной из наиболее часто используемых практик веб-разработки интерфейса. Динамический рендеринг списка часто используется для предоставления пользователю серии подобно сгруппированной информации в коротком и удобном формате. Мы видим это почти в каждом веб-приложении, которое мы используем списки содержимого во многих областях программы.
В этой статье мы разберемся с Vue v-for
директива в разработке динамических списков. Мы также рассмотрим несколько примеров, почему key
При этом следует использовать атрибут.
Поскольку мы будем подробно объяснять вещи, когда начинаем писать код, эта статья предусматривает, что у вас нет или очень мало знаний о Vue (и/или другие фреймворки JavaScript).
Пример: Twitter
Мы собираемся использовать Twitter в качестве примера для этой статьи.
Когда мы вошли в систему и на главном индексном маршруте Twitter, мы имеем вид, подобный этому:

На домашней странице мы привыкли видеть список тенденций, список твитов, список потенциальных подписчиков. Содержимое, отображаемое в этих списках, зависит от множества факторов нашей истории Twitter, кем мы следим, наших лайков и тому подобное. В результате можно сказать, что все эти данные есть динамический.
Хотя эти данные получаются динамически, способ эти показанные данные остаются постоянными. Отчасти это связано с использованием многоразовые веб-компоненты.
К примеру, мы можем увидеть список твитов как список синглов tweet-component
предметов. Мы можем придумать tweet-component
как оболочка, принимающая такие данные, как имя пользователя, дескриптор, твиты и аватар, среди прочих частей, и просто отображает эти фрагменты в последовательной разметке.

Скажем, мы хотели бы отобразить список компонентов (например, список tweet-component
элементов) на основе большого источника данных, полученных с сервера. В Vue первое, что должно приходить в голову, чтобы это сделать, это v-for
директива.
Директива v-for
The v-for
Директива используется для просмотра списка элементов на основе источника данных. Директиву можно использовать в элементе шаблона и требует определенного синтаксиса, например:

Увидим это на примере на практике. Во-первых, мы предположим, что мы уже получили коллекцию данных твитов:
const tweets = [
{
id: 1,
name: 'James',
handle: '@jokerjames',
img: '
tweet: "If you don't succeed, dust yourself off and try again.",
likes: 10,
},
{
id: 2,
name: 'Fatima',
handle: '@fantasticfatima',
img: '
tweet: 'Better late than never but never late is better.',
likes: 12,
},
{
id: 3,
name: 'Xin',
handle: '@xeroxin',
img: '
tweet: 'Beauty in the struggle, ugliness in the success.',
likes: 18,
}
]
tweets
является коллекцией tweet
предметы с каждым tweet
содержит детали этого конкретного твита – уникальный идентификатор, имя/руководитель аккаунта, сообщение твита и т.д. Давайте теперь попытаемся использовать v-for
директива воспроизведения списка компонентов твита на основе этих данных.
Прежде всего, мы создадим экземпляр Vue – сердце программы Vue. Мы смонтируем/присоединим наш экземпляр к элементу DOM с идентификатором app
и назначить tweets
коллекция как часть объекта данных экземпляра.
new Vue({
el: '#app',
data: {
tweets
}
});
Теперь мы продолжим создавать a tweet-component
что наша v-for
Директива будет использоваться для просмотра списка. Мы будем использовать глобальный Vue.component
конструктор для создания компонента с именем tweet-component
:
Vue.component('tweet-component', {
template: `
<div class="tweet">
<div class="box">
<article class="media">
<div class="media-left">
<figure class="image is-64x64">
<img :src=" alt="Image">
</figure>
</div>
<div class="media-content">
<div class="content">
<p>
<strong>{{tweet.name}}</strong> <small>{{tweet.handle}}</small>
<br>
{{tweet.tweet}}
</p>
</div>
<div class="level-left">
<a class="level-item">
<span class="icon is-small"><i class="fas fa-heart"></i></span>
<span class="likes">{{tweet.likes}}</span>
</a>
</div>
</div>
</article>
</div>
</div>
`,
props: {
tweet: Object
}
});
Здесь стоит обратить внимание на несколько интересных вещей:
- The
tweet-component
ожидает аtweet
объект опорный, как показано в требовании проверки prop (props: {tweet: Object}
). Если компонент отображается с помощью atweet
опора, то есть не объектVue будет выдавать предупреждение. - Мы привязываем свойства объекта твита к шаблону компонента с помощью синтаксиса Mustache:
{{ }}
. - Разметка компонента адаптирует элемент Bulma’s Box, поскольку он очень похож на твит.
В шаблоне HTML нужно создать разметку, куда будет смонтирована наша программа Vue (т.е. элемент с идентификатором) app
). В рамках этой разметки мы будем использовать v-for
директива для воспроизведения списка твитов.
Так как tweets
это сбор данных, который мы будем повторять, tweet
будет подходящим псевдонимом для использования в директиве. В каждом нанесенном tweet-component
Ну также перейти в повторенный tweet
объект в качестве реквизита для доступа к нему в компоненте.
<div id="app" class="columns">
<div class="column">
<tweet-component v-for="tweet in tweets" :tweet="tweet"/>
</div>
</div>
Независимо от как многое больше объектов твитов будет введено в коллекцию или то, как они будут меняться со временем — наши настройки всегда будут отображать все твиты в коллекции в той же разметке, которую мы ожидаем.
С помощью специального CSS наше приложение будет выглядеть примерно так:
Смотрите фильм Pen Simple Twitter №1 от Hassan Dj (@itslit) на CodePen.
Хотя все работает, как ожидалось, нам может быть предложена подсказка Vue на консоли браузера:
[Vue tip]: <tweet-component v-for="tweet in tweets">: component lists rendered with v-for should have explicit keys...
Примечание: Вы можете не видеть предупреждение на консоли браузера при выполнении кода через CodePen.
Почему Vue говорит нам указывать явные ключи в нашем списке, когда все работает, как ожидалось?
Ключевой атрибут
Обычной практикой является указывать ключевой атрибут для каждого повторяющегося элемента в обработанном изображении v-for
список. Это потому, что Vue использует key
атрибут для создания уникальные привязки для идентификации каждого узла.
Объясним это еще немного — если в нашем списке были какие-то динамические изменения пользовательского интерфейса (например, порядок элементов списка перемешивается), Vue выберет изменение данных в каждом элементе вместо этого перемещение элементов DOM соответственно. В большинстве случаев это не станет проблемой. Однако в определенных случаях, когда наша v-for
список зависит от состояния DOM и/или состояния дочернего компонента, это может привести к нежелательному поведению.
Давайте посмотрим на пример этого. Что если наш простой компонент твита теперь содержал поле ввода, которое позволит пользователю непосредственно ответить на сообщение твита? Мы игнорируем, как можно отправить этот ответ, и просто обратимся к самому новому полю ввода:

Мы включим это новое поле ввода в шаблон tweet-component
:
Vue.component('tweet-component', {
template: `
<div class="tweet">
<div class="box">
// ...
</div>
<div class="control has-icons-left has-icons-right">
<input class="input is-small" placeholder="Tweet your reply..." />
<span class="icon is-small is-left">
<i class="fas fa-envelope"></i>
</span>
</div>
</div>
`,
props: {
tweet: Object
}
});
Предположим, что мы хотели ввести еще одну новую функцию в наше приложение. Эта функция будет включать разрешение пользователя случайным образом перемешивать список твитов.
Для этого мы можем сначала включить Shuffle! кнопку в нашем шаблоне HTML:
<div id="app" class="columns">
<div class="column">
<button class="is-primary button" @click="shuffle">
Shuffle!
</button>
<tweet-component v-for="tweet in tweets" :tweet="tweet"/>
</div>
</div>
Мы присоединили прослушиватель события клика к элементу кнопки, чтобы вызвать a shuffle
метод при запуске В нашем экземпляре Vue мы создадим файл shuffle
метод, отвечающий за случайное перемешивание tweets
сбор в экземпляре. Для достижения этого мы будем использовать метод _shuffle lodash:
new Vue({
el: '#app',
data: {
tweets
},
methods: {
shuffle() {
this.tweets = _.shuffle(this.tweets)
}
}
});
Давайте попробуем! Если мы несколько раз нажмем перемешать, мы заметим, что наши элементы твитов будут случайным образом сортироваться с каждым щелчком.
Просмотрите ленту Pen Simple Twitter №2 от Hassan Dj (@itslit) на CodePen.
Однако если мы введем некоторую информацию во входные данные каждого компонента и потом щелкните перемешивать, мы заметим, что происходит что-то необычное:

Поскольку мы не решили использовать key
Vue не создал уникальные привязки к каждому узлу твитов. В результате, когда мы стремимся изменить порядок твитов, Vue использует более эффективный подход к сохранению, чтобы просто изменить (или патч) данные по каждому элементу. Поскольку временное состояние DOM (т.е. введенный текст) остается на месте, мы чувствуем это непреднамеренное несоответствие.
Вот диаграмма, которая показывает нам данные, прилагаемые к каждому элементу, и состояние DOM, которое остается на месте:

Чтобы избежать этого; нам придется назначить уникальный ключ каждому tweet-component
представлены в списке.
Мы будем использовать id
а tweet
быть уникальным идентификатором, поскольку мы должны безопасно сказать твит id
не должно быть равно другим. Поскольку мы используем динамические значения, мы будем использовать v-bind
директиву, чтобы привязать наш ключ к tweet.id
:
<div id="app" class="columns">
<div class="column">
<button class="is-primary button" @click="shuffle">
Shuffle!
</button>
<tweet-component
v-for="tweet in tweets"
:tweet="tweet"
:key="tweet.id"
/>
</div>
</div>
Теперь Vue распознает идентичность каждого узла твита, так что так и будет изменить порядок компонентов, когда мы намерены перетасовать список.

Переходы
Поскольку каждый компонент твита теперь перемещается соответствующим образом, мы можем шагнуть дальше и использовать Vue transition-group
к показать как изменяется порядок частей.
Для этого мы добавим transition-group
элемент как обертка до v-for
список. Мы укажем название перехода tweets
и объявляют, что группа перехода должна быть представлена как a div
элемент.
<div id="app" class="columns">
<div class="column">
<button class="is-primary button" @click="shuffle">
Shuffle!
</button>
<transition-group name="tweets" tag="div">
<tweet-component
v-for="tweet in tweets"
:tweet="tweet"
:key="tweet.id"
/>
</transition-group>
</div>
</div>
На основе названия перехода Vue автоматически распознает, были ли указаны переходы/анимации CSS. Поскольку мы стремимся вызвать переход для движение элементов в списке, Vue будет искать указанный переход CSS вдоль строк tweets-move
(где tweets
это название, данное нашей переходной группе).
В результате мы вручную введем a .tweets-move
класс, имеющий указанный тип и время перехода:
#app .tweets-move {
transition: transform 1s;
}
Примечание: Это очень краткий обзор применения переходов списка. Обязательно просмотрите документы Vue, чтобы получить подробную информацию о различных типах переходов, которые можно применить!
Наши tweet-component
элементы будут сейчас перехода соответствующим образом между локациями, когда вызывается перемешивание. Попробуй! Введите некоторую информацию в поле ввода и нажмите «Shuffle!» несколько раз.
Достаточно круто, правда? Без key
атрибут, элемент Transmission-group нельзя использовать для создания переходов списка поскольку элементы есть залатан на месте вместо того, чтобы быть переупорядоченным.
Следует ли key
атрибут всегда использоваться? Это рекомендовано. В документах Vue указано, что атрибут key следует опускать только в следующих случаях:
- Мы намеренно хотим, чтобы из соображений производительности использовался способ исправления элементов по умолчанию.
- Содержимое DOM достаточно простое.
Вывод
И вот у нас! Надеюсь, эта краткая статья показала, насколько полезным v-for
директива, а также предоставлено немного больше контекста, чем key
атрибут часто используется. Дайте мне знать, если у вас могут возникнуть вопросы/мысли!
Если вам понравился мой стиль письма и вы потенциально заинтересованы в том, чтобы научиться создавать реальные программы с помощью Vue, вам понравится книга Fullstack Vue: Полное руководство по Vue.js что я помог опубликовать! Книга охватывает многочисленные аспекты Vue, включая маршрутизацию, простое управление состоянием, обработку форм, Vuex, сохранение сервера и тестирование среди других тем. Если вы заинтересованы и/или хотите попробовать образец раздела, вы можете получить дополнительную информацию на нашем веб-сайте https://fullstack.io/vue!
Если у вас возникнут вопросы/мысли/мысли, вы можете связаться со мной в любое время @djirdehh!