Vue中的this.$set()使用方法详解(一文搞懂)

 更新时间:2025年09月06日 11:52:54   作者:前端页面仔  
this.$set是Vue中的一个方法,用于在响应式对象上设置新的属性或修改已有的属性,强制刷新并确保这些属性也是响应式的,这篇文章主要介绍了Vue中this.$set()使用方法的相关资料,需要的朋友可以参考下

前言

在 Vue.js 开发中,this.$set() 是一个解决响应性问题的关键工具。本文将从基础使用到高级场景,全面解析这个方法的使用技巧和最佳实践。

为什么需要this.$set()?——响应性原理的核心问题

Vue 的响应性系统无法检测对象属性的添加或删除,以及数组索引访问的变化。这是因为 Vue 2 使用 Object.defineProperty() 实现响应性,它存在以下限制:

// 对象属性添加问题
const obj = { name: 'John' };
this.person = obj;

// 添加新属性 - Vue 无法检测
this.person.age = 30; // ❌ 非响应式

// 数组索引修改问题
this.numbers = [1, 2, 3];
this.numbers[1] = 99; // ❌ 非响应式

这些情况下,视图不会自动更新,这时就需要 this.$set() 出马。

基本语法和参数解析

this.$set() 的完整语法如下:

this.$set(target, propertyName/index, value)
  • ​target​​:要修改的目标对象或数组(必需)
  • ​propertyName/index​​:要添加或修改的属性名或数组索引(必需)
  • ​value​​:要设置的值(必需)

使用场景和示例

场景1:为响应式对象添加新属性

export default {
  data() {
    return {
      user: {
        name: 'Alice',
        email: 'alice@example.com'
      }
    }
  },
  methods: {
    addUserAge() {
      // 错误方式 ❌
      // this.user.age = 25; // 视图不会更新
      
      // 正确方式 ✅
      this.$set(this.user, 'age', 25);
      
      // 验证
      console.log(this.user); // 包含 age 属性,视图会更新
    }
  }
}

场景2:修改数组指定索引的值

export default {
  data() {
    return {
      colors: ['red', 'green', 'blue']
    }
  },
  methods: {
    updateColor(index, newColor) {
      // 错误方式 ❌
      // this.colors[index] = newColor; // 视图不会更新
      
      // 正确方式 ✅
      this.$set(this.colors, index, newColor);
    }
  }
}

场景3:修改嵌套对象中的属性

export default {
  data() {
    return {
      company: {
        name: 'TechCorp',
        departments: {
          engineering: {
            manager: 'John',
            size: 50
          }
        }
      }
    }
  },
  methods: {
    updateManager(name) {
      // 为嵌套对象添加新属性
      this.$set(this.company.departments.engineering, 'manager', name);
      
      // 修改已有属性(等效直接赋值但确保响应性)
      this.$set(this.company.departments.engineering, 'size', 55);
    }
  }
}

原理揭秘:$set()背后的魔法

this.$set() 实际上是对全局 Vue.set() 方法的别名,其核心实现逻辑是:

  1. 判断目标是否是响应式对象
  2. 如果对象已有该属性:
    • 直接更新值
    • 触发相关依赖更新
  3. 如果对象没有该属性:
    • 将新属性转为响应式
    • 通知依赖更新
  4. 如果是数组且索引存在:
    • 使用 splice 方法修改数组
    • 触发数组更新检测
// 伪代码实现
function set(target, key, val) {
  // 如果是数组且索引有效
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.length = Math.max(target.length, key);
    target.splice(key, 1, val);
    return val;
  }
  
  // 如果对象已存在该属性
  if (key in target && !(key in Object.prototype)) {
    target[key] = val;
    return val;
  }
  
  // 获取目标对象的观察者实例
  const ob = target.__ob__;
  
  // 如果是非响应式对象,直接赋值
  if (!ob) {
    target[key] = val;
    return val;
  }
  
  // 将新属性转为响应式
  defineReactive(ob.value, key, val);
  
  // 通知依赖更新
  ob.dep.notify();
  return val;
}

高级应用场景

动态表单字段管理

<template>
  <div>
    <div v-for="(field, index) in dynamicForm" :key="index">
      <input v-model="field.value" :placeholder="field.placeholder">
      <button @click="removeField(index)">Remove</button>
    </div>
    <button @click="addField">Add Field</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dynamicForm: []
    }
  },
  methods: {
    addField() {
      const newIndex = this.dynamicForm.length;
      
      // 使用 $set 确保新字段响应式
      this.$set(this.dynamicForm, newIndex, {
        value: '',
        placeholder: `Field ${newIndex + 1}`
      });
    },
    removeField(index) {
      // 使用 splice 确保响应式
      this.dynamicForm.splice(index, 1);
    }
  }
}
</script>

基于权限的动态数据展示

<template>
  <div>
    <div v-if="user.permissions.viewSalary">
      <p>Salary: {{ user.salary }}</p>
    </div>
    <button @click="grantSalaryAccess">Grant Salary Access</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: {
        name: 'Bob',
        permissions: {
          viewSalary: false
        }
      }
    }
  },
  methods: {
    grantSalaryAccess() {
      // 1. 添加权限属性
      this.$set(this.user.permissions, 'viewSalary', true);
      
      // 2. 添加工资字段(不会暴露给没有权限的用户)
      setTimeout(() => {
        // 使用 $set 确保响应式
        this.$set(this.user, 'salary', 8500);
      }, 1000);
    }
  }
}
</script>

最佳实践与注意事项

  1. ​避免不必要的使用​​:

    • 已有属性可以直接修改:this.existingProp = newValue
    • 数组元素修改尽量使用 push()pop()shift()unshift()splice() 等方法
  2. ​性能考虑​​:

    • 对大型对象深度使用 $set 可能有性能开销
    • 批量更新时考虑使用 Object.assign() 创建新对象
  3. ​替代方案​​:

    // 使用新对象替换旧对象
    this.user = {
      ...this.user,
      age: 30,
      title: 'Senior Developer'
    };
    
    // 对于数组
    this.colors = this.colors.map((color, index) => 
      index === 1 ? 'purple' : color
    );
  4. ​Vue 3 的变化​​:

    • Vue 3 使用 Proxy 解决响应性限制
    • $set 在 Vue 3 中主要为兼容性保留
    • 在 Vue 3 中可直接添加新属性:this.newProperty = value

常见问题解决方案

问题:使用$set后视图仍未更新?

​解决方案​​:

  1. 确保在 Vue 实例方法中使用(生命周期钩子、方法等)
  2. 检查目标对象是否在 Vue 的响应系统中(data 返回或 Vue.observable 创建)
  3. 使用 this.$forceUpdate() 作为最后手段(不推荐)

问题:深度嵌套对象如何处理?

​解决方案​​:

// 使用自定义工具方法
setNestedProperty(obj, path, value) {
  const keys = path.split('.');
  const lastKey = keys.pop();
  let current = obj;
  
  keys.forEach(key => {
    if (!current[key]) this.$set(current, key, {});
    current = current[key];
  });
  
  this.$set(current, lastKey, value);
}

// 使用示例
this.setNestedProperty(this.app, 'settings.theme.color', 'dark-blue');

总结

this.$set() 是 Vue 响应式系统的关键补充工具,尤其适用于:

  • 动态添加新属性到已存在对象
  • 通过索引修改数组元素
  • 确保深度嵌套属性的响应式更新

掌握 this.$set() 的使用场景和替代方案,能帮助开发者更高效地构建响应式 Vue 应用,避免常见的响应性问题。在 Vue 3 中,由于 Proxy 的引入,大部分场景不再需要 $set,但对于 Vue 2 项目,这仍是必备工具。

到此这篇关于Vue中this.$set()使用方法的文章就介绍到这了,更多相关Vue this.$set()使用方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue3中Teleport的用法以及使用场景小结

    vue3中Teleport的用法以及使用场景小结

    Teleport是一个内置组件,它可以将一个组件内部的一部分模板传送到该组件的 DOM 结构外层的位置去,本文主要介绍了Vue3中Teleport用法以及使用场景小结,感兴趣的可以了解一下
    2025-04-04
  • electron+vite+vue3 快速入门实例教程

    electron+vite+vue3 快速入门实例教程

    Electron、Vite 和 Vue 3 结合使用可以创建强大的跨平台桌面应用程序,下面是一个快速入门教程,帮助你搭建一个基于 Electron + Vite + Vue 3 的项目,感兴趣的朋友一起看看吧
    2025-05-05
  • mpvue构建小程序的方法(步骤+地址)

    mpvue构建小程序的方法(步骤+地址)

    mpvue是一个使用Vue.js开发小程序的前端框架。框架基于 Vue.js 核心,这篇文章主要介绍了mpvue构建小程序的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • vue2+element-ui使用vue-i18n进行国际化的多语言/国际化详细教程

    vue2+element-ui使用vue-i18n进行国际化的多语言/国际化详细教程

    这篇文章主要给大家介绍了关于vue2+element-ui使用vue-i18n进行国际化的多语言/国际化的相关资料,I18n是Vue.js的国际化插件,项目里面的中英文等多语言切换会使用到这个东西,需要的朋友可以参考下
    2023-12-12
  • vue实现滚动条滚动到底部时发送请求获取数据方式

    vue实现滚动条滚动到底部时发送请求获取数据方式

    文章介绍了通过监听滚动事件和判断滚动条位置来实现自动分页加载数据的功能,从而无需手动点击分页按钮,主要原理是通过比较`clientHeight`、`scrollTop`和`scrollHeight`的值,当滚动条滚动到底部时触发下一页数据的加载
    2025-12-12
  • 解决vue prop传值default属性如何使用,为何不生效的问题

    解决vue prop传值default属性如何使用,为何不生效的问题

    这篇文章主要介绍了解决vue prop传值default属性如何使用,为何不生效的问题。具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • Vue如何设置全局css文件以及css组合器

    Vue如何设置全局css文件以及css组合器

    这篇文章主要介绍了Vue如何设置全局css文件以及css组合器问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • 基于Vue2实现数字纵向滚动效果

    基于Vue2实现数字纵向滚动效果

    这篇文章主要为大家详细介绍了如何基于Vue2实现数字纵向滚动效果,从而达到显示计时器滚动效果,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-03-03
  • 聊聊element-ui 侧边栏的router问题

    聊聊element-ui 侧边栏的router问题

    这篇文章主要介绍了关于element-ui 侧边栏的router问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • vue elementUI下拉框值无法选中问题及解决方案

    vue elementUI下拉框值无法选中问题及解决方案

    大家在写系统的时候,会有这样的需求:点击修改后把需要修改的数据放入表单,其中会有下拉单选框、下拉多选框,展示下拉框单选框内的数据只需要将所选id赋值给下拉框绑定的值就可以了,下面给大家分享vue elementUI下拉框值无法选中问题,感兴趣的朋友一起看看吧
    2024-03-03

最新评论