vue $set怎么实现给数组集合对象赋值

发布时间:2022-04-26 08:20:12 作者:iii
来源:亿速云 阅读:1389
# Vue $set 怎么实现给数组集合对象赋值

## 一、Vue 响应式原理与 $set 的诞生背景

### 1.1 Vue 的响应式系统局限性
Vue 2.x 使用 `Object.defineProperty` 实现响应式,这种实现存在两个主要限制:

1. **无法检测对象属性的添加/删除**
2. **数组变更的特殊情况**:
   - 通过索引直接设置项(`arr[index] = newValue`)
   - 修改数组长度(`arr.length = newLength`)

### 1.2 为什么需要 $set
当我们需要动态给响应式对象添加新属性,或修改数组特定索引的值时,直接赋值不会触发视图更新。这时就需要使用 `Vue.set` 或实例方法 `this.$set`。

```javascript
// 不会触发更新
this.arr[1] = 'new value' 
this.obj.newProp = 'value'

// 正确做法
this.$set(this.arr, 1, 'new value')
this.$set(this.obj, 'newProp', 'value')

二、$set 的核心实现解析

2.1 源码位置(Vue 2.x)

$set 方法定义在 src/core/observer/index.js 中:

export 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
}

2.2 数组处理的特殊逻辑

对于数组操作,$set 内部实际上使用了 splice 方法,这是因为 Vue 重写了数组的变异方法(push/pop/shift/unshift/splice/sort/reverse),使得这些方法能够触发响应式更新。

// 等效操作
this.$set(arr, index, value)
// 等同于
arr.splice(index, 1, value)

三、$set 的实际应用场景

3.1 动态添加对象属性

export default {
  data() {
    return {
      user: {
        name: '张三'
      }
    }
  },
  methods: {
    addAge() {
      // 错误方式
      // this.user.age = 25 // 不会响应
      
      // 正确方式
      this.$set(this.user, 'age', 25)
    }
  }
}

3.2 修改数组元素

export default {
  data() {
    return {
      items: ['a', 'b', 'c']
    }
  },
  methods: {
    updateItem(index) {
      // 错误方式
      // this.items[index] = 'x' // 不会响应
      
      // 正确方式
      this.$set(this.items, index, 'x')
      
      // 替代方案(同样有效)
      // this.items.splice(index, 1, 'x')
    }
  }
}

3.3 动态添加嵌套属性

export default {
  data() {
    return {
      formData: {}
    }
  },
  methods: {
    initForm() {
      // 多层嵌套需要逐层设置
      this.$set(this.formData, 'contact', {})
      this.$set(this.formData.contact, 'phone', '')
    }
  }
}

四、$set 的替代方案比较

4.1 使用 Vue 3 的 reactive

在 Vue 3 中,基于 Proxy 的响应式系统不再需要 $set:

import { reactive } from 'vue'

const state = reactive({})
state.newProp = 'value' // 自动响应

4.2 使用 Object.assign

对于对象,可以创建新对象触发更新:

this.user = Object.assign({}, this.user, { age: 25 })

4.3 数组的特殊方法

对于数组,优先使用变异方法:

// 替换元素
this.items.splice(index, 1, newItem)

// 添加元素
this.items.push(newItem)

五、$set 的注意事项

  1. 不能用于根级响应式属性

    // 错误!不能直接添加根级属性
    this.$set(this, 'newProp', value)
    
  2. 性能考虑

    • 频繁使用 $set 可能影响性能
    • 对于批量操作,建议先处理数据再整体赋值
  3. 与 v-model 的配合: “`html


## 六、总结

`$set` 是 Vue 2.x 响应式系统的重要补充,它解决了以下关键问题:
- 动态添加响应式属性
- 数组索引直接赋值
- 确保嵌套属性的响应性

在 Vue 3 中,由于 Proxy 的实现,大多数情况下不再需要 `$set`,但在 Vue 2.x 项目中,它仍然是处理动态响应式数据的利器。

**最佳实践建议**:
1. 初始化时尽量声明所有响应式属性
2. 必须动态添加时优先使用 `$set`
3. 数组操作优先使用变异方法
4. 复杂数据结构考虑使用 Vuex 或 Pinia 管理状态

通过合理运用 `$set` 方法,可以确保你的 Vue 应用始终保持正确的响应式行为。
推荐阅读:
  1. vue $set 给数据赋值的实例
  2. 茶余饭后聊聊Vue3.0响应式数据那些事儿

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

vue $set

上一篇:Java面向对象之多态实例分析

下一篇:Vue项目中常用的实用技巧有哪些

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》