浅谈 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>

相关推荐
kyriewen5 小时前
Anthropic 估值逼近万亿美元,Claude Sonnet 5 + Claude Science 一天两连发
前端·ai编程·claude
小徐_23337 小时前
Wot UI 2.2.0 发布:Button 新增 subtle,VideoPreview 预览体验继续增强
前端·微信小程序·uni-app
天蓝色的鱼鱼9 小时前
关于 CSS 你可能不知道的属性,但关键时刻很有用
前端·css
泯泷10 小时前
第 2 篇:设计第一套字节码:Opcode、Instruction 与 Constant Pool
前端·javascript·安全
妙码生花10 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十五):优化细节、网络请求封装
前端·后端·ai编程
泯泷10 小时前
第 1 篇:从 1 + 2 开始:亲手写出第一台 JSVM
前端·javascript·安全
团团崽_七分甜10 小时前
Spring Boot 核心知识点总结
前端
lichenyang45310 小时前
从一个按钮开始,理解 ASCF 框架到底在做什么
前端
古夕10 小时前
第三方 SSO 接入实践:redirect_uri 编码、回调一致性与跨项目联调
前端·vue.js