0


Vue.set()的使用,以及对其进行深入解析

Vue.set()使用

vue 在实例上添加新的属性的时候,该属性,并不是响应式的。同样删除某一属性的时候,也不会实时渲染到页面上。

    比如:

年龄:{{obj.age? obj.age: "无"}}

    ···········      

data() {

        return {        

            obj:{ name:"Lena", id:1 },

        }

      }

页面上 显示的是 **年龄:无 **现在需要添加一个响应式的属性 age

<template>
<div class="app">
      <ul>
        <li> 年龄:{{obj.age? obj.age: "无"}}</li>
      </ul>
      <button @click="add()">添加年龄属性</button>
      <button @click="show()">打印</button>
</div>
</template>

<script>
import Vue from 'vue'
export default {
  component:{},
  data() {
    return {
        obj:{ name:"Lena", id:1 },
    }
  },
  methods: {
    add(){
      this.obj.age= 20
    },
    show(){
      console.log('obj',this.obj)
    }
  }
}
</script>

效果:

通过** this.obj.age= 20** ,控制台打印已经有了该属性,并没有渲染到页面上。 可见,这种方式添加的属性 **age **并不是响应式的。

使用Vue.set() ,更改add()方法:

add(){
      Vue.set(this.obj,'age', '20')
    },

效果:

因为vue不能检测到对象属性的添加或者删除,只有在data对象上存在的属性是响应式的,所以要使用Vue.set()方法将响应式属性添加到对象上。同样的道理,删除对象 Vue.delete也是如此。

Vue.delete()的使用

<template>
<div class="app">
      <ul>
        <li> 年龄:{{obj.age? obj.age: "无"}}</li>
      </ul>
      <button @click="add()">添加年龄属性</button>
      <button @click="del()">删除年龄属性</button>
      <button @click="show()">打印</button>
</div>
</template>
<script>
import Vue from 'vue'
export default {
  component:{

  },
  data() {
    return {
        obj:{ name:"Lena", id:1 },
    }
  },
  methods: {
    add(){
      Vue.set(this.obj,'age', '20')
    },
    del(){
      Vue.delete(this.obj,'age')
    },
    show(){
      console.log('obj',this.obj)
    }
  }
}
</script>

效果:

del() 方法如果是下面两种,同样不是响应式的。

del(){

  delete this.obj.age

},

或者:

del(){

  this.obj = { name:"Lena", id:1 }

},

Vue.set()方法原理解析

    我们找到封装set方法的地方:**.........\node_modules\vue\src\core\observer\index.js**

找到封装的set方法:

export function set (target: Array<any> | Object, key: any, val: any): any {
  if (process.env.NODE_ENV !== 'production' &&
    (isUndef(target) || isPrimitive(target))
  ) {
    warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)
  }
  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: any).__ob__
  if (target._isVue || (ob && ob.vmCount)) {
    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
  }
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

对象调用:**Vue.set( target ,'age', 20 ) **

数组调用****Vue.set( array , 0, 20 ) ** //数组对象,索引,值


    首先是判断是否是开发环境并且 对象是否被定义**isUndef(target**)或者是否是**基础类型isPrimitive(target)**,否则会报错:

Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}

if (process.env.NODE_ENV !== 'production' &&

(isUndef(target) || isPrimitive(target))

)


    如果是数组的话,调用重写的splice()方法,可以更新视图。

    **isValidArrayIndex(key)**方法用来验证是否是一个有效的数组索引, 其实就是验证是否是一个非无穷大的正整数。

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

}


如果是Vue实例,或者是根数据data的时候,就会报错。

如果本身就不是响应式的,只需要直接赋值即可。

const ob = (target: any).__ob__
  //如果是Vue实例,或者是根数据data的时候,就会报错。
  if (target._isVue || (ob && ob.vmCount)) {
    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
  }
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val

排除各种不合适的,最后给当前对象定义一个属性:**defineReactive(ob.value, key, val) **相当于用了 **Object.defineProperty **重新定义了一下。

最后,手动通知视图更新:ob.dep.notify()

总结

这个 set方法,对于数组来说,调用的就是splice,对于对象来说,使用的就是defineReactive,再添加了一个手动的视图更新。这就是set的原理。


本文转载自: https://blog.csdn.net/m0_62021563/article/details/128530829
版权归原作者 天命爱心职责~ 所有, 如有侵权,请联系我们删除。

“Vue.set()的使用,以及对其进行深入解析”的评论:

还没有评论