Vue 6. 列表渲染

本文主要包含以下知识点:

  • 使用 v-for 进行列表渲染
  • 数组更新检测

使用 v-for 进行列表渲染

使用 v-for 指令根据一组数组的选项列表进行渲染。v-for 指令需要使用 item in items 形式的特殊语法,items 是源数据数组,item 是数组元素迭代的别名。

下面是一个 v-for 的示例:

<body>
    <div id="app">
        <p v-for="item in items">my name is {{ item.name }}I'm {{ item.age }} years old.</p>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                items: [
                    {'name' : 'xiejie','age' : 18},
                    {'name' : 'yajing','age' : 20},
                    {'name' : 'xizhi','age' : 2}
                ]
            }
        });
    </script>
</body>

效果:
在这里插入图片描述
v-for 还支持一个可选的第二个参数为当前项的索引。

示例如下:

<body>
    <div id="app">
        <p v-for="(item,index) in items">{{ index+1 }}. my name is {{ item.name }}I'm {{ item.age }} years old.</p>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                items: [
                    {'name' : 'xiejie','age' : 18},
                    {'name' : 'yajing','age' : 20},
                    {'name' : 'xizhi','age' : 2}
                ]
            }
        });
    </script>
</body>

效果:
在这里插入图片描述
也可以使用 v-for 来迭代一个对象。

示例如下:

<body>
    <div id="app">
        <ul>
            <!--1 个参数为值 ,2 个参数为键 ,3 个参数为索引 -->
            <li v-for="(value,key,index) in stu">{{ index+1 }}. {{ key }} : {{ value }}</li>
        </ul>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                stu: {
                    name: 'xiejie',
                    age: 18,
                    gender: 'male',
                    score: 100
                }
            }
        });
    </script>
</body>

效果:
在这里插入图片描述
v-for 也可以取整数。在这种情况下,它将重复多次模板。

例如:

<body>
    <div id="app">
        <ul>
            <li v-for="n in 5">{{ n }}</li>
        </ul>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
        });
    </script>
</body>

效果:
在这里插入图片描述
类似于 v-if,可以利用带有 v-fortemplate 渲染多个元素。

比如:

<body>
    <div id="app">
        <ul>
            <template v-for="item in items">
                <li>name:{{ item.name }}</li>
                <li>age:{{ item.age }}</li>
                <li>gender:{{ item.male }}</li>
                <hr>
            </template>
        </ul>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data : {
                items : [
                    {'name':'xiejie','age':18,'gender':'male'},
                    {'name':'yajing','age':20,'gender':'female'},
                    {'name':'xizhi','age':2,'gender':'male'},
                ]
            }
        });
    </script>
</body>

效果:
在这里插入图片描述

使用 key

Vuev-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。

如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。

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

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

理想的 key 值是每项都有的唯一 id

例如:

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

数组更新检测

当数组里面的数据发生更新时,Vue 会检测到其更新,然后自动重新渲染视图。更新数组的方法可以分为 2 大类:变异方法非变异方法

变异方法

所谓变异方法,是指在调用了该方法后会改变原本的数组。

Vue 包含一组观察数组的变异方法,它们将会触发视图更新。

具体包含以下方法:

  • push:接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。
  • pop:从数组末尾移除最后一项,减少数组的 length 值,然后返回移除的项。
  • shift:移除数组中的第一个项并返回该项,同时数组的长度减 1
  • unshift:在数组前端添加任意个项并返回新数组长度。
  • splice:删除原数组的一部分成员,并可以在被删除的位置添加入新的数组成员。
  • sort:调用每个数组项的 toString 方法,然后比较得到的字符串排序,返回经过排序之后的数组。
  • reverse:用于反转数组的顺序,返回经过排序之后的数组。

下面我们来看一个具体的示例:

<body>
    <div id="example">
        <div>
            <button @click='push'>push</button>
            <button @click='pop'>pop</button>
            <button @click='shift'>shift</button>
            <button @click='unshift'>unshift</button>
            <button @click='splice'>splice</button>
            <button @click='sort'>sort</button>
            <button @click='reverse'>reverse</button>
        </div>
        <ul>
            <li v-for="item in items">
                {{ item.name }}
            </li>
        </ul>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const vm = new Vue({
            el: '#example',
            data: {
                items: [
                    { name : 'xiejie'}, 
                    { name : 'yajing'},
                    { name : 'xizhi'}
                ],
                addValue: { name: 'newGuy'}
            },
            methods: {
                push() {
                    this.items.push(this.addValue)
                },
                pop() {
                    this.items.pop()
                },
                shift() {
                    this.items.shift()
                },
                unshift() {
                    this.items.unshift(this.addValue)
                },
                splice() {
                    this.items.splice(0, 1)
                },
                sort() {
                    this.items.sort()
                },
                reverse() {
                    this.items.reverse()
                }
            }
        })
    </script>
</body>

效果:
在这里插入图片描述

非变异方法

除了上面所列举的变异方法以外,JavaScript 中也存在不会改变原来数组的非变异方法。这个时候,我们可以使用新数组来替换旧数组。

常见的非变异方法如下:

  • concat:先创建当前数组的副本,然后将接收到的参数添加到该副本的末尾,最后返回新构建的数组。
  • slice:基于当前数组中一个或多个项创建一个新数组,接受一个或两个参数,即要返回项的起始和结束位置,最后返回新数组。
  • map:对数组的每一项运行给定函数,返回每次函数调用的结果组成的数组。
  • filter:对数组中的每一项运行给定函数,该函数会返回 true 的项组成的数组。

具体示例如下:

<body>
    <div id="app">
        <div>
            <button @click='concat'>concat</button>
            <button @click='slice'>slice</button>
            <button @click='map'>map</button>
            <button @click='filter'>filter</button>
        </div>
        <ul>
            <li v-for="item in items">
                {{ item }}
            </li>
        </ul>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                items: ['xiejie', 'yajing', 'xizhi'],
                addValue: 'newGuy'
            },
            methods: {
                concat() {
                    this.items = this.items.concat(this.addValue); // 拼接新的值
                },
                slice() {
                    this.items = this.items.slice(1); // 移除第一个数据
                },
                map() {
                    // 每一项数据前面拼接索引
                    this.items = this.items.map(function (item, index, arr) {
                        return index + item;
                    })
                },
                filter() {
                    // 返回索引大于 0 的数据
                    this.items = this.items.filter(function (item, index, arr) {
                        return (index > 0);
                    });
                }
            }
        })
    </script>
</body>

效果:
在这里插入图片描述

无法检测的数组变化

Vue 中无法检测到以下 2 种变异的形式:

  • 利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
  • 修改数组的长度时,例如:vm.items.length = newLength

不过,针对上面的 2 种情况,我们也有相应的对策。

如果要设置数组某一个具体的项目,可以使用 Vue 实例的 set 方法。而如果要改变数组的长度,可以使用 splice 来进行替代。

下面是一个具体的示例:

<body>
    <div id="app">
        <!-- 特别需要注意的是以下的数组变动方法是不支持的:
                通过索引直接设置项:app.books[2] = {...}
                修改数组长度:app.books.length = 1 -->
        <input type="text" name="" id="" placeholder="请输入书名" v-model='newBookName'>
        <input type="text" name="" id="" placeholder="请输入作者" v-model='newBookAuthor'>
        <button @click='editOne'>设置第一本书的信息</button>
        <p>购买的书如下:</p>
        <ul>
            <template v-for='(book,index) in books'>
                <li>序号:{{index}}</li>
                <li>书名:{{book.name}}</li>
                <li>作者:{{book.author}}</li>
                <li>-------------------------</li>
            </template>
        </ul>
        <button @click='remainOne'>只留下第一本书</button>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                newBookName: '', // 和第一个文本框的数据相关联
                newBookAuthor: '', // 和第二个文本框的数据相关联
                books: [
                    {'name': '科学用脑','author': '郭勇'},
                    {'name': 'Vue入门','author': '梁灏'},
                    {'name': '日语会话','author': '谢杰'},
                    {'name': 'PS高级技巧','author': '沈文靖'},
                ]
            },
            methods: {
                // 如果要设置数组某一个具体的项目,可以使用 Vue 实例的 set 方法
                editOne: function () {
                    Vue.set(this.books, 0, {
                        'name': this.newBookName,
                        'author': this.newBookAuthor
                    });
                },
                // 如果要改变数组的长度,可以使用splice来进行替代
                remainOne: function () {
                    this.books.splice(1);
                }
            }
        });
    </script>
</body>

效果:设置第一本书信息的功能涉及到了改变数组具体的某一个元素,需要使用 Vue 实例的 set 方法。而只留下第一本书的功能,涉及到了改变数组的长度,在不能直接设置数组 length 属性的情况下,我们选择使用 splice 方法来实现。

在这里插入图片描述

注:还可以使用 vm.$set 实例方法,它只是全局 Vue.set 的别名。

显示过滤和排序结果

有时,我们想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。

在这种情况下,可以创建返回过滤或排序数组的计算属性。

例如:

<body>
    <div id="app">
        <ul>
            <li v-for="n in evenNumbers">{{ n }}</li>
        </ul>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                numbers: [1, 2, 3, 4, 5]
            },
            computed: {
                evenNumbers: function () {
                    return this.numbers.filter(function (number) {
                        return number % 2 === 0
                    })
                }
            }
        });
        // 原有的数组没有改变
        console.log(vm.numbers); // [1, 2, 3, 4, 5]
    </script>
</body>

效果:
在这里插入图片描述

注:在计算属性不适用的情况下,可以使用一个 method 方法来代替计算属性。

总结

  1. 使用 v-for 可以进行列表渲染。v-for 指令需要使用 item in items 形式的特殊语法。

  2. Vuev-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。

  3. Vue 包含一组观察数组的变异方法,它们将会触发视图更新。

  4. 如果是非变异方法,我们可以使用新数组来替换旧数组。

  5. 如果要设置数组某一个具体的项目,可以使用 Vue 实例的 set 方法。而如果要改变数组的长度,可以使用 splice 来进行替代。

  6. 如果想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据,可以创建返回过滤或排序数组的计算属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值