浅谈 Vue2 数组对象新增属性,响应式失效问题

需求

在工作中我们可能有这样的需求,就是对数据进行改造,有时我们需要对原来的数据添加一些额外属性,以达到控制页面的效果。

需求如下(简单举例):

我们需要对页面进行点击,对点击到的数据进行变色,最后在提交的时候,我们需要把这些变色的数据提取出来,应该怎么做呢?

这个时候就需要对原始数据进行改造了,我们需要在原始的数据结构上面添加一个 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>

相关推荐
lilu88888881 小时前
AI代码生成器赋能房地产:ScriptEcho如何革新VR/AR房产浏览体验
前端·人工智能·ar·vr
LCG元1 小时前
Vue.js组件开发-实现对视频预览
前端·vue.js·音视频
阿芯爱编程1 小时前
vue3 react区别
前端·react.js·前端框架
烛.照1032 小时前
Nginx部署的前端项目刷新404问题
运维·前端·nginx
YoloMari2 小时前
组件中的emit
前端·javascript·vue.js·微信小程序·uni-app
浪浪山小白兔2 小时前
HTML5 Web Worker 的使用与实践
前端·html·html5
疯狂小料3 小时前
React 路由导航与传参详解
前端·react.js·前端框架
追光少年33224 小时前
Learning Vue 读书笔记 Chapter 2
前端·javascript·vue.js·vue3
前端熊猫4 小时前
JavaScript 的 Promise 对象和 Promise.all 方法的使用
开发语言·前端·javascript
iOS阿玮4 小时前
速领🧧!iOS研究院专属「红包封面」来了,第二弹。
前端