Movatterモバイル変換


[0]ホーム

URL:


Skip to content

ViteConf 2025 · First timein-person · Amsterdam · Oct 09-10 Register

Vue.js

List Rendering

v-for

We can use thev-for directive to render a list of items based on an array. Thev-for directive requires a special syntax in the form ofitem in items, whereitems is the source data array anditem is analias for the array element being iterated on:

js
const items = ref([{ message:'Foo' }, { message:'Bar' }])
js
data() {  return {    items: [{ message:'Foo' }, { message:'Bar' }]  }}
template
<li v-for="itemin items">  {{ item.message }}</li>

Inside thev-for scope, template expressions have access to all parent scope properties. In addition,v-for also supports an optional second alias for the index of the current item:

js
const parentMessage = ref('Parent')const items = ref([{ message:'Foo' }, { message:'Bar' }])
js
data() {  return {    parentMessage:'Parent',    items: [{ message:'Foo' }, { message:'Bar' }]  }}
template
<li v-for="(item, index)in items">  {{ parentMessage }} - {{ index }} - {{ item.message }}</li>
  • Parent - 0 - Foo
  • Parent - 1 - Bar
  • The variable scoping ofv-for is similar to the following #"Copy Code">js

    const parentMessage = 'Parent'const items = [  /* ... */]items.forEach((item,index)=> {  // has access to outer scope `parentMessage`  // but `item` and `index` are only available in here  console.log(parentMessage, item.message, index)})

    Notice how thev-for value matches the function signature of theforEach callback. In fact, you can use destructuring on thev-for item alias similar to destructuring function arguments:

    template
    <li v-for="{ message }in items">  {{ message }}</li><!-- with index alias --><li v-for="({ message }, index)in items">  {{ message }} {{ index }}</li>

    For nestedv-for, scoping also works similar to nested functions. Eachv-for scope has access to parent scopes:

    template
    <li v-for="itemin items">  <span v-for="childItemin item.children">    {{ item.message }} {{ childItem }}  </span></li>

    You can also useof as the delimiter instead ofin, so that it is closer to JavaScript's syntax for iterators:

    template
    <div v-for="itemof items"></div>

    v-for with an Object

    You can also usev-for to iterate through the properties of an object. The iteration order will be based on the result of callingObject.values() on the object:

    js
    const myObject = reactive({  title:'How to do lists in Vue',  author:'Jane Doe',  publishedAt:'2016-04-10'})
    js
    data() {  return {    myObject: {      title:'How to do lists in Vue',      author:'Jane Doe',      publishedAt:'2016-04-10'    }  }}
    template
    <ul>  <li v-for="valuein myObject">    {{ value }}  </li></ul>

    You can also provide a second alias for the property's name (a.k.a. key):

    template
    <li v-for="(value, key)in myObject">  {{ key }}: {{ value }}</li>

    And another for the index:

    template
    <li v-for="(value, key, index)in myObject">  {{ index }}. {{ key }}: {{ value }}</li>

    v-for with a Range

    v-for can also take an integer. In this case it will repeat the template that many times, based on a range of1...n.

    template
    <span v-for="nin 10">{{ n }}</span>

    Note heren starts with an initial value of1 instead of0.

    v-for on<template>

    Similar to templatev-if, you can also use a<template> tag withv-for to render a block of multiple elements. For example:

    template
    <ul>  <template v-for="itemin items">    <li>{{ item.msg }}</li>    <li class="divider" role="presentation"></li>  </template></ul>

    v-for withv-if

    When they exist on the same node,v-if has a higher priority thanv-for. That means thev-if condition will not have access to variables from the scope of thev-for:

    template
    <!--This will throw an error because property "todo"is not defined on instance.--><li v-for="todoin todos" v-if="!todo.isComplete">  {{ todo.name }}</li>

    This can be fixed by movingv-for to a wrapping<template> tag (which is also more explicit):

    template
    <template v-for="todoin todos">  <li v-if="!todo.isComplete">    {{ todo.name }}  </li></template>

    Note

    It'snot recommended to usev-if andv-for on the same element due to implicit precedence.

    There are two common cases where this can be tempting:

    • To filter items in a list (e.g.v-for="user in users" v-if="user.isActive"). In these cases, replaceusers with a new computed property that returns your filtered list (e.g.activeUsers).

    • To avoid rendering a list if it should be hidden (e.g.v-for="user in users" v-if="shouldShowUsers"). In these cases, move thev-if to a container element (e.g.ul,ol).

    Maintaining State withkey

    When Vue is updating a list of elements rendered withv-for, by default it uses an "in-place patch" strategy. If the order of the data items has changed, instead of moving the DOM elements to match the order of the items, Vue will patch each element in-place and make sure it reflects what should be rendered at that particular index.

    This default mode is efficient, butonly suitable when your list render output does not rely on child component state or temporary DOM state (e.g. form input values).

    To give Vue a hint so that it can track each node's identity, and thus reuse and reorder existing elements, you need to provide a uniquekey attribute for each item:

    template
    <div v-for="itemin items" :key="item.id">  <!-- content --></div>

    When using<template v-for>, thekey should be placed on the<template> container:

    template
    <template v-for="todoin todos" :key="todo.name">  <li>{{ todo.name }}</li></template>

    Note

    key here is a special attribute being bound withv-bind. It should not be confused with the property key variable whenusingv-for with an object.

    It is recommended to provide akey attribute withv-for whenever possible, unless the iterated DOM content is simple (i.e. contains no components or stateful DOM elements), or you are intentionally relying on the default behavior for performance gains.

    Thekey binding expects primitive values - i.e. strings and numbers. Do not use objects asv-for keys. For detailed usage of thekey attribute, please see thekey API documentation.

    v-for with a Component

    This section assumes knowledge ofComponents. Feel free to skip it and come back later.

    You can directly usev-for on a component, like any normal element (don't forget to provide akey):

    template
    <MyComponent v-for="itemin items" :key="item.id" />

    However, this won't automatically pass any data to the component, because components have isolated scopes of their own. In order to pass the iterated data into the component, we should also use props:

    template
    <MyComponent  v-for="(item, index)in items"  :item="item"  :index="index"  :key="item.id"/>

    The reason for not automatically injectingitem into the component is because that makes the component tightly coupled to howv-for works. Being explicit about where its data comes from makes the component reusable in other situations.

    Check outthis example of a simple todo list to see how to render a list of components usingv-for, passing different data to each instance.

    Check outthis example of a simple todo list to see how to render a list of components usingv-for, passing different data to each instance.

    Array Change Detection

    Mutation Methods

    Vue is able to detect when a reactive array's mutation methods are called and trigger necessary updates. These mutation methods are:

    • push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
    • reverse()

    Replacing an Array

    Mutation methods, as the name suggests, mutate the original array they are called on. In comparison, there are also non-mutating methods, e.g.filter(),concat() andslice(), which do not mutate the original array butalways return a new array. When working with non-mutating methods, we should replace the old array with the new one:

    js
    // `items` is a ref with array valueitems.value= items.value.filter((item)=> item.message.match(/Foo/))
    js
    this.items= this.items.filter((item)=> item.message.match(/Foo/))

    You might think this will cause Vue to throw away the existing DOM and re-render the entire list - luckily, that is not the case. Vue implements some smart heuristics to maximize DOM element reuse, so replacing an array with another array containing overlapping objects is a very efficient operation.

    Displaying Filtered/Sorted Results

    Sometimes we want to display a filtered or sorted version of an array without actually mutating or resetting the original data. In this case, you can create a computed property that returns the filtered or sorted array.

    For example:

    js
    const numbers = ref([1,2,3,4,5])const evenNumbers = computed(()=> {  return numbers.value.filter((n)=> n% 2 === 0)})
    js
    data() {  return {    numbers: [1,2,3,4,5]  }},computed: {  evenNumbers() {    return this.numbers.filter(n => n% 2 === 0)  }}
    template
    <li v-for="nin evenNumbers">{{ n }}</li>

    In situations where computed properties are not feasible (e.g. inside nestedv-for loops), you can use a method:

    js
    const sets = ref([  [1,2,3,4,5],  [6,7,8,9,10]])function even(numbers) {  return numbers.filter((number)=> number% 2 === 0)}
    js
    data() {  return {    sets: [[1,2,3,4,5 ], [6,7,8,9,10]]  }},methods: {  even(numbers) {    return numbers.filter(number => number% 2 === 0)  }}
    template
    <ul v-for="numbersin sets">  <li v-for="nin even(numbers)">{{ n }}</li></ul>

    Be careful withreverse() andsort() in a computed property! These two methods will mutate the original array, which should be avoided in computed getters. Create a copy of the original array before calling these methods:

    diff
    - return numbers.reverse()+ return [...numbers].reverse()

    Edit this page on GitHub

    List Rendering has loaded

    [8]ページ先頭

    ©2009-2025 Movatter.jp