Vue.js(8):列表渲染

一、用 v-for 把一个数组对应为一组元素

        我们可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名

<div id="app">
    <ul>
        <li v-for="item in items">
            {{ item.message }}
        </li>
    </ul>
</div>

<script>
    const app = Vue.createApp({
        data() {
            return {
                items: [{message: 'Foo'}, {message: 'Bar'}]
            }
        }
    });

    app.mount("#app");
</script>

        在 v-for 块中,我们可以访问所有父作用域的 property。v-for 还支持一个可选的第二个参数,即当前项的索引。

<div id="app">
    <ul>
<!--        v-for = (项目,索引) in 项目列表-->
        <li v-for="(item, index) in items">
<!--            在遍历中可以访问父作用域中的属性 parentMessage -->
            {{ parentMessage }} - {{ index }} - {{ item.message }}
        </li>
    </ul>
</div>

<script>
    const app = Vue.createApp({
        data() {
            return {
                parentMessage: 'Parent', // 其他信息
                items: [{ message: 'Foo' }, { message: 'Bar' }] // 遍历的数组
            }
        }
    });

    app.mount("#app");
</script>

        你也可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法:

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

二、在 v-for 里使用对象

        你也可以用 v-for 来遍历一个对象的 property。

<div id="app">
    <ul class="demo">
<!--        value将会是myObject对象拥有属性的值-->
        <li v-for="value in myObject">
            {{ value }}
        </li>
    </ul>
</div>

<script>
    const app = Vue.createApp({
        data() {
            return {
                myObject: { // myObject对象,并且拥有三个属性
                    title: 'How to do lists in Vue',
                    author: 'Jane Doe',
                    publishedAt: '2016-04-10'
                }
            }
        }
    });
    app.mount("#app");
</script>

        你也可以提供第二个的参数为 property 名称 (也就是键名 key):

<div id="app">
    <ul class="demo">
<!--        第二个参数name 是属性名-->
        <li v-for="(value, name) in myObject">
            {{ name }}: {{ value }}
        </li>
    </ul>
</div>

<script>
    const app = Vue.createApp({
        data() {
            return {
                myObject: { // myObject对象,并且拥有三个属性
                    title: 'How to do lists in Vue',
                    author: 'Jane Doe',
                    publishedAt: '2016-04-10'
                }
            }
        }
    });
    app.mount("#app");
</script>

        还可以用第三个参数作为索引:

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

        提示:在遍历对象时,会按 Object.keys() 的结果遍历,但是不能保证它在不同 JavaScript 引擎下的结果都一致。

三、维护状态

        当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。

        这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出

        为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute:

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

建议        建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。

        因为它是 Vue 识别节点的一个通用机制,key 并不仅与 v-for 特别关联。后面我们将在指南中看到,它还具有其它用途。

        提示:不要使用对象或数组之类的非基本类型值作为 v-for 的 key。请用字符串或数值类型的值。更多 key attribute 的细节用法请移步至 key 的 API 文档

四、数组更新检测

变更方法

        Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:

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

        你可以打开控制台,然后对前面例子的 items 数组尝试调用变更方法。比如 example1.items.push({ message: 'Baz' })

替换数组

        变更方法,顾名思义,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如 filter()concat() 和 slice()。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组:

// 给Vue的data中数组重新赋值
example1.items = example1.items.filter(item => item.message.match(/Foo/))

        你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。

五、显示过滤/排序后的结果

        有时,我们想要显示一个数组经过过滤或排序后的版本,而不实际变更或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数组。

<div id="app">
    <ul>
<!--        此处遍历的是计算属性过滤后的数组-->
        <li v-for="n in evenNumbers" :key="n">{{ n }}</li>
    </ul>
</div>

<script>
    const app = Vue.createApp({
        data() {
            return {
                numbers: [ 1, 2, 3, 4, 5 ]
            }
        },
        computed: {
            evenNumbers() { // 计算属性函数,过滤掉numbers数组中所有的奇数
                return this.numbers.filter(number => number % 2 === 0)
            }
        }
    });
    app.mount("#app");
</script>

        在计算属性不适用的情况下 (例如,在嵌套 v-for 循环中) 你可以使用一个方法:

<div id="app">
    <ul v-for="numbers in sets">
        <li v-for="n in even(numbers)" :key="n">{{ n }}</li>
    </ul>
</div>

<script>
    const app = Vue.createApp({
        data() {
            return {// 二维数组
                sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
            }
        },
        methods: { // 这里不能使用计算属性,需要外部传参
            even(numbers) { // 过滤掉二维数组中所有奇数
                return numbers.filter(number => number % 2 === 0)
            }
        }
    });
    app.mount("#app");
</script>

六、在 v-for 里使用值的范围

  v-for 也可以接受整数。在这种情况下,它会把模板重复对应次数。

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

 七、在 <template> 中使用 v-for

        类似于 v-if,你也可以利用带有 v-for 的 <template> 来循环渲染一段包含多个元素的内容。比如:

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

八、v-for 与 v-if 一同使用

        注意我们推荐在同一元素上使用 v-if 和 v-for。更多细节可查阅风格指南

        当它们处于同一节点,v-if 的优先级比 v-for 更高,这意味着 v-if 将没有权限访问 v-for 里的变量:

<!-- 这将抛出一个错误,因为属性“todo”没有在实例上定义。 -->
<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo.name }}
</li>

        可以把 v-for 移动到 <template> 标签中来修正:

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

九、在组件上使用 v-for

        在自定义组件上,你可以像在任何普通元素上一样使用 v-for

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

        然而,任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要使用 props:

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

        不自动将 item 注入到组件里的原因是,这会使得组件与 v-for 的运作紧密耦合。明确组件数据的来源能够使组件在其他场合重复使用。

下面是一个简单的 todo 列表的完整例子:

<div id="app">
<!--    v-on:submit.prevent 阻止表单自动提交-->
    <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>

<script>
    // 创建Vue
    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 // 下一个待办列表的id
            }
        },
        methods: {
            addNewTodo() { // 添加待办事项方法
                this.todos.push({ // 将输入的待办事项填入列表中
                    id: this.nextTodoId++,
                    title: this.newTodoText
                })
                this.newTodoText = '' // 清空输入框
            }
        }
    })
    // 向Vue中添加自定义组件
    // {{ title }} : v-for 绑定组件的 :title的值
    // @click="$emit('remove')" 点击事件 $emit('remove')表示调用父组件的remove事件
    app.component('todo-item', {
        template: `
    <li>
      {{ title }}
      <button @click="$emit('remove')">Remove</button>
    </li>
  `,
        props: ['title'],   // 属性列表
        emits: ['remove']   // 事件列表
    });

    app.mount("#app");
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

游王子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值