源码位置: vue/src/core/observer/index.js

/**
 * Set a property on an object. Adds the new property and
 * triggers change notification if the property doesn't
 * already exist.
 */
export function set (target: Array<any> | Object, key: any, val: any): any {
  /*如果传入数组则在指定位置插入val*/
  if (Array.isArray(target) && typeof key === 'number') {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, val)
    /*因为数组不需要进行响应式处理,数组会修改七个Array原型上的方法来进行响应式处理*/
    return val
  }
  /*如果是一个对象,并且已经存在了这个key则直接返回*/
  if (hasOwn(target, key)) {
    target[key] = val
    return val
  }
  /*获得target的Oberver实例*/
  const ob = (target : any).__ob__
  /*
    _isVue 一个防止vm实例自身被观察的标志位 ,_isVue为true则代表vm实例,也就是this
    vmCount判断是否为根节点,存在则代表是data的根节点,Vue 不允许在已经创建的实例上动态添加新的根级响应式属性(root-level reactive property)
  */
  if (target._isVue || (ob && ob.vmCount)) {
    /*  
      Vue 不允许在已经创建的实例上动态添加新的根级响应式属性(root-level reactive property)。
      https://cn.vuejs.org/v2/guide/reactivity.html#变化检测问题
    */
    process.env.NODE_ENV !== 'production' && warn(
      'Avoid adding reactive properties to a Vue instance or its root $data ' +
      'at runtime - declare it upfront in the data option.'
    )
    return val
  }
  if (!ob) {
    target[key] = val
    return val
  }
  /*为对象defineProperty上在变化时通知的属性*/
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

测试代码

<template>
 <div id="app">
  <p v-for="(item,index) in items" :key="index">{{item.name}},{{item.id}},{{item.add}}</p>
  <button class="btn" @click="handClick()">更新数据</button>
 </div>
</template>

<script>
export default {
 name: 'App',
 data () {
  return {
   items: [
        { name: "111", id: "1" },
        { name: "222", id: "2" },
        { name: "333", id: "3" }
      ],
  }
 },
 mounted () {
   // this.$set(this.items,0,art) //$set 可以触发更新视图
 },
 methods: {
  handClick(){
   let change = this.items[0]
   change.name="666"
   this.$set(this.items,0,change) //$set(数组对象,被修改的对象索引值,修改内容)
   this.$set(this.items,3,change) //$set(数组对象,被修改的对象索引值,修改内容)如果不存在则会添加,但是在对象数组级别操作只能紧跟最后一个索引,如本例索引0,1,2;则添加时只能填3
   this.$set(this.items[0],'add','change') //$set(某一个对象,被修改对象中的key,修改key对应的值),如果在该对象中不存在该key,则将其连同值一起添加至该对象
   this.$set(this.items[1],'id','99')
   this.$set(this.items[2],'name','555')
  }
 }
}
</script>

<style>

</style>

结果
更新数据前
111,1,
222,2,
333,3,
更新数据后
666,1,change
222,99,
555,3,
666,1,change

Logo

前往低代码交流专区

更多推荐