Vue中对象数组改变其对象内容值数组没变化的原因与解决方案

 更新时间:2025年03月26日 11:17:34   作者:郡nionio  
最近开发遇到一个问题,修改对象某一个索引对象时,直接将对象赋值给数组的某一索引对象,该数组没变化,在 Vue 中,直接修改对象数组中某个对象的属性值时,数组的引用本身未改变,本文介绍了详细的原理分析和解决方案,需要的朋友可以参考下

一、数组的底层原理(JavaScript 角度)

1. 数组是引用类型

  • 数组变量存储的是指向堆内存中数组对象的引用地址
  • 修改数组中对象的属性值时,数组的引用地址未变,但堆内存中的对象内容被修改。
const arr = [{ name: 'Alice' }, { name: 'Bob' }];
const arrRef = arr; // 指向同一内存地址
arr[0].name = 'Alex'; // 修改堆内存中的对象,arr 和 arrRef 的引用地址未变

2. 数组操作的分类

  • 改变原数组(引用地址不变):push, pop, splice, 直接修改元素属性等。
  • 返回新数组(引用地址变化):map, filter, slice, 扩展运算符等。

二、Vue 响应式系统的核心机制

1. Vue 2 的响应式实现

  • 对象监听:通过 Object.defineProperty 递归劫持对象属性的 getter/setter。
  • 数组监听:重写数组的 7 个变异方法(push, pop, splice 等),但这些方法只能检测数组结构变化,无法检测元素属性变化
  • 直接修改对象属性的问题
this.list[0].name = 'Alex'; // Vue 2 无法检测到变化!

2. Vue 3 的响应式改进

  • 使用 Proxy 代理整个对象/数组,能检测深层属性变化(包括数组元素属性修改)。
  • 局限性:直接通过索引修改数组元素时,仍需遵循不可变原则(如使用 map 返回新数组)。

三、Vue 中“数组未变化”的根本原因

1. Vue 2 的场景

  • 直接修改对象属性
this.list[0].name = 'Alex'; // 修改成功,但视图不更新!

Vue 2 无法通过 Object.defineProperty 监听数组元素的属性变化。

  • 直接通过索引修改数组元素
this.list[0] = { name: 'Alex' }; // 视图不更新!

2. Vue 3 的场景

  • Proxy 的深度监听
const list = reactive([{ name: 'Alice' }]);
list[0].name = 'Alex'; // 视图会自动更新 ✅
  • 直接替换数组元素仍需注意
list[0] = { name: 'Alex' }; // 视图更新 ✅(Proxy 可检测索引变化)

四、解决方案:强制触发视图更新

1. Vue 2 的解决方案

  • 使用 Vue.set 或 this.$set
this.$set(this.list, 0, { ...this.list[0], name: 'Alex' });
  • 替换整个数组(创建新引用):
this.list = this.list.map(item => 
  item.id === targetId ? { ...item, key: newVal } : item
);

2. Vue 3 的解决方案

  • 直接修改属性(Proxy 自动监听):
const list = ref([{ name: 'Alice' }]);
list.value[0].name = 'Alex'; // 自动更新 ✅
  • 不可变更新(推荐)
list.value = list.value.map(item => 
  item.id === targetId ? { ...item, key: newVal } : item
);

五、总结:关键原则

  • 不可变数据(Immutability)

    • 始终返回新数组/新对象,确保引用地址变化。
    • 使用 map, filter, 扩展运算符等非破坏性方法。
  • Vue 2 的特殊处理

    • 修改数组元素属性时,必须用 Vue.set 或替换整个数组。
  • Vue 3 的优势

    • 利用 Proxy 的深度监听,直接修改对象属性可触发更新。

示例代码(Vue 2 不可变更新)

// 修改数组中某个对象的属性
this.list = this.list.map(item => {
  if (item.id === targetId) {
    return { ...item, name: 'New Name' };
  }
  return item;
});

六、附加:数组操作的响应式兼容表

操作类型Vue 2 是否触发更新Vue 3 是否触发更新
arr.push()
arr[index] = newValue
arr.splice()
修改对象属性 arr[index].key = value

以上就是Vue中对象数组改变其对象内容值数组没变化的原因与解决方案的详细内容,更多关于Vue对象数组改变内容值没变的资料请关注脚本之家其它相关文章!

相关文章

  • Vue集成和使用SQLite的完整指南

    Vue集成和使用SQLite的完整指南

    SQLite 是一种轻量级的关系型数据库管理系统,以其简单易用、无需服务器等特点广泛应用于嵌入式系统、移动应用和小型应用程序中,在 Vue.js 项目中使用 SQLite,可以将应用的数据存储在客户端,本文将介绍如何在 Vue 项目中集成 SQLite,需要的朋友可以参考下
    2024-11-11
  • vue form 表单提交后刷新页面的方法

    vue form 表单提交后刷新页面的方法

    今天小编就为大家分享一篇vue form 表单提交后刷新页面的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • iview form清除校验状态的实现

    iview form清除校验状态的实现

    这篇文章主要介绍了iview form清除校验状态的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • 使用vue开发移动端管理后台的注意事项

    使用vue开发移动端管理后台的注意事项

    这篇文章主要介绍了使用vue开发移动端管理后台的注意事项,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • 22个Vue优化技巧(项目实用)

    22个Vue优化技巧(项目实用)

    演示代码使用 Vue3 + ts + Vite 编写,但是也会列出适用于 Vue2 的优化技巧,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • vue长按事件和点击事件冲突的解决

    vue长按事件和点击事件冲突的解决

    这篇文章主要介绍了vue长按事件和点击事件冲突的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • Vue移动端下拉刷新组件的使用教程

    Vue移动端下拉刷新组件的使用教程

    这篇文章主要介绍了Vue移动端下拉刷新组件的使用教程,每一次我在使用vant组件库里面list组件和下拉刷新连在一起用的时候都会出现下拉刷新和列表下滑局部滚动的冲突,这就很难受,这篇文章将解决它
    2023-04-04
  • 实现shallowReadonly和isProxy功能示例详解

    实现shallowReadonly和isProxy功能示例详解

    这篇文章主要为大家介绍了实现shallowReadonly和isProxy功能示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Vue中使用jsencrypt进行RSA非对称加密的操作方法

    Vue中使用jsencrypt进行RSA非对称加密的操作方法

    这篇文章主要介绍了Vue中使用jsencrypt进行RSA非对称加密,在这里需要注意要加密的数据必须是字符串,对Vue RSA非对称加密相关知识感兴趣的朋友一起看看吧
    2022-04-04
  • 用electron打包vue项目中的报错问题及解决

    用electron打包vue项目中的报错问题及解决

    这篇文章主要介绍了用electron打包vue项目中的报错问题及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05

最新评论