[翻译] vue3指南--08List Rendering 列表渲染__Vue.js
发布于 4 年前 作者 banyungong 1250 次浏览 来自 分享
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利

Mapping an Array to Elements with v-forv-for把数组映射成元素.

We can use the v-for directive to render a list of items based on an array. The v-for directive requires a special syntax in the form of item in items, where items is the source data array and item is an alias for the array element being iterated on:

可以是用v-for指令去渲染一组数组数据.v-for指令必须依照item in items这种语法格式——items是源数组名,item是将要迭代的数组中每个元素的别名:

<ul id="array-rendering">
  <li v-for="item in items">
    {{ item.message }}
  </li>
</ul>
Vue.createApp({
  data() {
    return {
      items: [{ message: 'Foo' }, { message: 'Bar' }]
    }
  }
}).mount('#array-rendering')

Result:

See the Pen v-for with Array by Vue ([@Vue](/user/Vue)) on CodePen.

<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

Inside v-for blocks we have full access to parent scope properties. v-for also supports an optional second argument for the index of the current item.

v-for块内,我们有父级域所有属性(properties)的访问权限. v-for也支持(可选的)第二参数,用来表示当前item的index值.

<ul id="array-with-index">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>
Vue.createApp({
  data() {
    return {
      parentMessage: 'Parent',
      items: [{ message: 'Foo' }, { message: 'Bar' }]
    }
  }
}).mount('#array-with-index')

Result:

See the Pen v-for with Array and index by Vue ([@Vue](/user/Vue)) on CodePen.

<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

You can also use of as the delimiter instead of in, so that it is closer to JavaScript’s syntax for iterators:

你也可以使用of代替in作为分隔符. 这样更贴近JS的迭代器语法.

<div v-for="item of items"></div>

v-for with an Object

You can also use v-for to iterate through the properties of an object.

也可以用v-for去遍历一个对象的属性(property)值.

<ul id="v-for-object" class="demo">
  <li v-for="value in myObject">
    {{ value }}
  </li>
</ul>
Vue.createApp({
  data() {
    return {
      myObject: {
        title: 'How to do lists in Vue',
        author: 'Jane Doe',
        publishedAt: '2016-04-10'
      }
    }
  }
}).mount('#v-for-object')

Result:

See the Pen v-for with Object by Vue ([@Vue](/user/Vue)) on CodePen.

<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

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

也可以提供第二个参数——表示对象属性key名.

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

See the Pen v-for with Object and key by Vue ([@Vue](/user/Vue)) on CodePen.

<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

And another for the index:

还可以再加一个index.

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

See the Pen v-for with Object key and index by Vue ([@Vue](/user/Vue)) on CodePen.

<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

:::tip Note When iterating over an object, the order is based on the enumeration order of Object.keys(), which isn’t guaranteed to be consistent across JavaScript engine implementations. :::

Note 提示. 当遍历一个对象时, 遍历顺序基于Object.keys()方法的枚举顺序,(因为JS引擎们实现方法未必一直.)所以无法保证跨引擎的顺序一致性.

Maintaining State 状态保持.

When Vue is updating a list of elements rendered with v-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.

当Vue更新一个由v-for渲染的元素列表时,默认使用"原地置换"策略. 如果数据项的顺序变了,Vue不会去改变Dom元素的顺序去匹配数据项的数据,而是原地更新每个元素,保证他按正确index渲染.

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

这种默认模式更高效,但 只在列表的渲染结果不依赖子组件状态,也不依赖临时dom状态(如,来自input值)的时候适合

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 unique key attribute for each item:

为了给Vue一个提示——保证它可以跟踪每个节点的身份,这样就可以复用和重新排序已有元素——需要给每项都添加一个唯一的key属性(attribute)

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

It is recommended to provide a key attribute with v-for whenever possible, unless the iterated DOM content is simple, or you are intentionally relying on the default behavior for performance gains.

建议尽可能在使用v-for时候提供一个key属性(attribute),除非,要遍历的DOM内容很简单或者你有意用默认行为来提高性能.

Since it’s a generic mechanism for Vue to identify nodes, the key also has other uses that are not specifically tied to v-for, as we will see later in the guide.

由于这是一个Vue识别节点的通用机制,key属性(attribute)不是只能和v-for绑定使用,其他的用处在指南后面会见到.

:::tip Note Don’t use non-primitive values like objects and arrays as v-for keys. Use string or numeric values instead. :::

提示 不要使用一些非基本类型值作为v-for的key值.使用字符串或者数字值.

For detailed usage of the key attribute, please see the key API documentation.

key属性(attribut)更多使用细节,可以参见key API 文档.

Array Change Detection 数组更新检测

Mutation Methods 变更方法们.

Vue wraps an observed array’s mutation methods so they will also trigger view updates. The wrapped methods are:

Vue包裹了一些(被侦听的)数组(的一些变更)方法——这样,调用这些方法时候也会触发视图更新.被Vue包裹的方法有:

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

You can open the console and play with the previous examples’ items array by calling their mutation methods. For example: example1.items.push({ message: 'Baz' }).

可以打开console,玩一下之前的例子.调用上面的变更方法去改变之前那些例子里的items.比如, example1.items.push({ message: 'Baz' }).

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() and slice(), which do not mutate the original array but always return a new array. When working with non-mutating methods, you can replace the old array with the new one:

变更方法,如其名,当调用时候变更原数组. 相比之下, 有一些非变更方法. 比如:filter(), concat()slice().这些方法不改变原数组,却 返回新数组. 当使用这些非变更方法时,你可以把旧数组用新数组替换.

example1.items = example1.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.

你可能会觉得,这会让Vue丢掉已有DOM去重新渲染整个列表.但是事实不是这样,Vue实现了一些 启发式/探索式算法去极大的复用DOM元素,所以用一些包含重复对象的新数组去替换原数组是高效操作.

Displaying Filtered/Sorted Results 显示Filtered/Sorted结果

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.

有时,我们想要显示一些被 过滤或者排序的 数组,但是并不改变这些原数据.这种case,可以建立一个computed属性(还记得吗)——在这里返回你想要的数组.

For example:

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

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

有些computed属性不适用(比如嵌套在一个v-for循环内)的时候,你可以使用methods

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

v-for with a Range v-for用于范围

v-for can also take an integer. In this case it will repeat the template that many times.

v-for也可以接收一个整数. 这样会将模版重复相应次数

<div id="range" class="demo">
  <span v-for="n in 10">{{ n }} </span>
</div>

Result:

See the Pen v-for with a range by Vue ([@Vue](/user/Vue)) on CodePen.

<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

v-for on a <template> v-for用于<template>

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

类似template的v-if,也可以在一个<template>标签上使用v-for去渲染一系列元素.比如:

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

v-for with v-if v-forv-if 同时

:::tip Note that it’s not recommended to use v-if and v-for together. Refer to style guide for details. :::

v-forv-if同时使用是 不建议的. 更多相关查看风格指南

When they exist on the same node, v-for has a higher priority than v-if. That means the v-if will be run on each iteration of the loop separately. This can be useful when you want to render nodes for only some items, like below:

当他们在相同节点同时存在的时候,v-for有更高优先级.这意味这,v-if将在循环的每次迭代中单独运行. 如果你想只渲染表内某些项的时候,是有用的:

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

The above only renders the todos that are not complete.

上面值渲染未完成的todos.

If instead, your intent is to conditionally skip execution of the loop, you can place the v-if on a wrapper element (or <template>). For example:

如果,你的目的是按条件跳过整个循环,你可以把v-if放在一个包裹元素上(或<template>),比如:

<ul v-if="todos.length">
  <li v-for="todo in todos">
    {{ todo }}
  </li>
</ul>
<p v-else>No todos left!</p>

v-for with a Component

This section assumes knowledge of Components. Feel free to skip it and come back later. 这节认为你已经懂了Components.可以先跳过,之后再来看

You can directly use v-for on a custom component, like any normal element:

你可以直接在一个自定义组件上用v-for——和普通元素无差:

<my-component v-for="item in items" :key="item.id"></my-component>

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:

然而,这样不会自动传数据到组件,因为组件有他们自己的独立域(isolated scope).为了将各遍历项传进组件,还应该使用props

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

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

item不自动注入组件的原因是,如果自动注入会让组件和v-for运作机制紧密耦合. 显示声明数据来源使组件在其他情境下可复用.

Here’s a complete example of a simple todo list:

下面,一个简单todo list的完整例子:

<div id="todo-list-example">
  <form v-on:submit.prevent="addNewTodo">
    <label for="new-todo">Add a todo</label>
    <input
      v-model="newTodoText"
      id="new-todo"
      placeholder="E.g. Feed the cat"
    />
    <button>Add</button>
  </form>
  <ul>
    <todo-item
      v-for="(todo, index) in todos"
      :key="todo.id"
      :title="todo.title"
      @remove="todos.splice(index, 1)"
    ></todo-item>
  </ul>
</div>
const app = Vue.createApp({
  data() {
    return {
      newTodoText: '',
      todos: [
        {
          id: 1,
          title: 'Do the dishes'
        },
        {
          id: 2,
          title: 'Take out the trash'
        },
        {
          id: 3,
          title: 'Mow the lawn'
        }
      ],
      nextTodoId: 4
    }
  },
  methods: {
    addNewTodo() {
      this.todos.push({
        id: this.nextTodoId++,
        title: this.newTodoText
      })
      this.newTodoText = ''
    }
  }
})

app.component('todo-item', {
  template: `
    <li>
      {{ title }}
      <button @click="$emit('remove')">Remove</button>
    </li>
  `,
  props: ['title']
})

app.mount('#todo-list-example')

See the Pen v-for with components by Vue ([@Vue](/user/Vue)) on CodePen.

<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

疑惑🤔

版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 作者: Frankie_S 原文链接:https://juejin.im/post/6865427018675126279

回到顶部