需求
在工作中我们可能有这样的需求,就是对数据进行改造,有时我们需要对原来的数据添加一些额外属性,以达到控制页面的效果。
需求如下(简单举例):
我们需要对页面进行点击,对点击到的数据进行变色,最后在提交的时候,我们需要把这些变色的数据提取出来,应该怎么做呢?
这个时候就需要对原始数据进行改造了,我们需要在原始的数据结构上面添加一个 checked 属性来标识是否进行点击或者选中,默认为 false,点击之后为 true,最后通过 filter 把 checked 为 true 的筛选出来即可,接下来演示一下。
ini
this.dataBack = [
{
value: '测试',
},
{
value: '测试',
},
]
this.dataBack.forEach((item) => {
item.checked = false
})
可以看到,数据已经改造成功。
接下来我们拿到数据后就可以进行相关的点击操作了,下面是实现代码。
less
<div>
<div v-for="(item, index) in dataBack" :key="index">
<span
:style="{
color: item.checked ? 'red' : 'gray',
}"
@click="changeState(index)"
>{{ item.value }}{{ item.checked }}</span
>
</div>
</div>
javascript
changeState(index) {
this.dataBack[index].checked = !this.dataBack[index].checked
console.log(' this.dataBack: ', this.dataBack)
},
我写了一个简单的样式,就是点击之后改变 span 的颜色,默认为 gray,点击之后为 red,按理说点击之后 index 对应的 checked 会取反,vue监听到 checked 为 true 时就会改变颜色,接下来看一下效果
就在我们觉得任务已经完成的时候,这个时候问题出现了!我先后点击了第一个和第二个,我们看到控制台的数据已经发生变化了,但是奇怪的是页面字体颜色和 checked 还是为 false,那么问题是什么呢?
原因
在给深层次的数据赋值或者给对象添加新的属性,页面上的数据并不会同步更新,这是因为 Vue 2不能检测到对象属性的添加或者删除,所以vue不允许在已经定义好的数据上动态的添加新的属性值。至于为什么,这里不做讲解,想了解的可以看下这篇文章blog.csdn.net/weixin_4344...
解决一
知道了原因,就好解决了,既然 Vue 不允许进行添加数据,或者说检测不到新增属性的变化,那么我们就不添加了,我们直接进行赋值,我们把处理好的数据直接丢给 Vue ,这样总行了吧?
javascript
let arr = [
{
value: '测试',
},
{
value: '测试',
},
]
arr.forEach((item) => {
item.checked = false
})
this.dataBack = arr
console.log(' this.dataBack: ', this.dataBack)
我们使用变量去接收数据,对变量进行改造,然后将变量赋值给 Vue,这样 Vue 接收到的就是一个完整的数据了,我并没有对 Vue 直接进行添加属性,这下总可以监听到了吧?
果不其然,效果实现了。
解决二
使用 this.$set 进行赋值,也可以检测到变化,同样为响应式,这种写法也是常用的,不仅使用于这个场景,还适用于组件传值去修改深层次属性值,具体用法可以参考这篇文章。blog.csdn.net/lzfengquan/...
代码如下:
kotlin
this.dataBack = [
{
value: '测试',
},
{
value: '测试',
},
]
this.dataBack.forEach((item) => {
this.$set(item, 'checked', false)
})
总结
当我们对 Vue 的深层次数据结构进行改造时,不可以直接对 Vue 数据进行添加属性,而是应该先对数据进行改造,然后将改造好的数据赋值给 Vue ,或者使用 this.$set 进行修改,这下 Vue 才可以检测到数据的变化,这也是在工作中经常使用的方法,希望可以帮助到大家,有什么写的不对的地方,大家也可以评论一起交流。
附上全部代码,大家可以自己试试。
xml
<template>
<div>
<div v-for="(item, index) in dataBack" :key="index">
<span
:style="{
color: item.checked ? 'red' : 'gray',
}"
@click="changeState(index)"
>{{ item.value }}{{ item.checked }}</span
>
</div>
<button @click="submit">提交</button>
</div>
</template>
<script>
export default {
name: 'DataTest',
data() {
return {
dataBack: [],
}
},
created() {
//方案一
let arr = [
{
value: '测试',
},
{
value: '测试',
},
]
arr.forEach((item) => {
item.checked = false
})
this.dataBack = arr
//方案二
// this.dataBack = [
// {
// value: '测试',
// },
// {
// value: '测试',
// },
// ]
// this.dataBack.forEach((item) => {
// this.$set(item, 'checked', false)
// })
console.log(' this.dataBack: ', this.dataBack)
},
methods: {
changeState(index) {
this.dataBack[index].checked = !this.dataBack[index].checked
console.log(' this.dataBack: ', this.dataBack)
},
submit() {
let data = this.dataBack.filter((item) => item.checked)
console.log('data: ', data)
},
},
}
</script>