一、$set的作用和语法结构
$set是uniapp框架提供的一种方法,可以对data中的数据进行修改和更新。$set的语法结构如下:
Vue.set(object, key, value)或vm.$set(object, key, value)
其中object必填,是要修改的对象;key必填,是对象中要修改或更新的属性名;value必填,是属性的新值。
二、$set的常见应用场景
在vue.js的开发中,可以通过直接对data中的数据进行修改来实现对视图的更新,但当需要修改或更新对象中某个属性的时候,如果直接对属性进行修改,vue.js无法监测到数据的变化,也就无法触发视图更新。这时就需要使用$set方法来通知vue.js数据改变了,视图需要更新。下面是$set的常见应用场景。
1、通过数组下标更新数组数据
如果需要修改数组中的某个元素,可以通过数组下标来更新数组数据。例如,有一个tasks数组,需要将第一个任务的状态由未完成改为已完成,可以使用以下代码实现:
this.tasks[0].status = 'completed';
上面的代码可以更新数据,但是vue.js无法检测到数据的变化,这时就需要使用$set来通知vue.js更新数据。代码如下:
this.$set(this.tasks[0], 'status', 'completed');
这样vue.js就能检测到数据的变化,触发视图的更新。
2、通过对象属性名更新对象数据
如果需要修改对象中的某个属性,也可以使用$set来触发视图更新。例如,有一个person对象,需要将其年龄属性值改为20,可以使用以下代码实现:
this.person.age = 20;
同样,这样修改数据vue.js也无法检测到数据变化,需要使用$set方法来通知vue.js更新数据。代码如下:
this.$set(this.person, 'age', 20);
三、$set的高级操作——监听对象属性的新增与删除
除了可以对已有属性进行修改和更新,$set方法还支持监听对象属性的新增和删除。这一功能对于实现动态表单、涉及到属性的动态添加和删除的组件非常有用。
1、新增属性
如果需要给对象新增一个属性,并且希望vue.js能够监测到新增的属性,可以使用$set方法。例如,有一个person对象,需要新增一个地址属性,可以使用以下代码实现:
this.$set(this.person, 'address', '');
这样新增属性就可以被vue.js监测到,从而使得视图更新。
2、删除属性
如果需要删除对象中的某个属性,同样可以使用$set方法。例如,有一个person对象,需要删除其地址属性,可以使用以下代码实现:
this.$set(this.person, 'address', undefined);
这样操作会使得地址属性变为undefined,但是vue.js依然会监测到属性的删除,使得视图更新。
四、$set的注意事项
$set虽然非常实用,但是在使用过程中也需要注意一些问题,防止出现不必要的错误和问题。
1、避免在模板中使用$set
虽然$set方法可以帮助我们实现动态数据的更新,但是在模板中使用$set是非常不推荐的。在模板中可以直接使用data中的数据和方法,可以不必使用$set。如果需要在组件中进行动态数据更新,可以借助computed、watch和props等特性来实现。
2、避免在computed属性中使用$set
在computed计算属性中,如果使用$set方法进行数据更新,会导致无限循环的问题。因为computed属性的值是基于data中的其他属性计算的,如果在computed中使用$set方法,则会让computed属性的值发生变化,从而引起重新计算,这样就形成了循环调用。
3、$set无法监控属性名的变化
$set方法只能监听对象属性值的变化,无法监听属性名的变化。比如,如果一个对象中的属性名称发生了变化,$set方法是无法监测到这一变化,并且也无法触发组件的更新。所以在修改属性名时,需要手动删除原有属性并在对象中添加一个新的属性,从而实现属性名的修改和更新。
五、$set的实例应用
下面是一个$set的实例应用,代码中实现了一个待办事项的功能,支持添加任务、修改任务状态和删除任务。
1、模板中的代码
<template> <div class="task-list"> <h3>待办事项</h3> <ul> <li v-for="(task, index) in tasks" :key="index"> <input type="checkbox" v-model="task.status"> <span :class="{ completed: task.status }" v-text="task.title"></span> <i class="iconfont icon-delete" @click="deleteTask(index)"></i> </li> </ul> <form @submit.prevent="addTask"> <input type="text" v-model="newTaskContent"> <button type="submit">添加任务</button> </form> </div> </template>
2、script中的代码
<script> export default { data () { return { tasks: [ { title: '吃饭', status: true }, { title: '睡觉', status: false }, { title: '打豆豆', status: false } ], newTaskContent: '' } }, methods: { addTask () { if (this.newTaskContent.trim() !== '') { this.tasks.push({ title: this.newTaskContent, status: false }) this.newTaskContent = '' } }, deleteTask (index) { this.tasks.splice(index, 1) } } } </script>
3、style中的代码
<style scoped> .task-list { margin: 20px auto; padding: 20px; box-shadow: 0 0 10px rgba(0,0,0,.1); } .task-list h3 { font-size: 24px; margin-bottom: 20px; } .task-list ul { list-style: none; padding: 0; } .task-list li { display: flex; align-items: center; margin-bottom: 10px; font-size: 18px; } .task-list input[type="checkbox"] { margin-right: 10px; } .task-list span.completed { text-decoration: line-through; color: #999; } .task-list i { margin-left: auto; cursor: pointer; font-size: 18px; } .task-list form { margin-top: 20px; } .task-list input[type="text"] { padding: 5px 10px; font-size: 18px; margin-right: 10px; border: none; border-bottom: 1px solid #999; outline: none; } .task-list button { padding: 5px 10px; font-size: 18px; background-color: #00bcd4; color: #fff; border: none; outline: none; cursor: pointer; } </style>
在这个例子中,我使用了$set方法来更新任务的状态,确保vue.js能够检测到数据变化从而更新视图。
this.$set(this.tasks[index], 'status', !this.tasks[index].status)