vue2 数据响应式Object.defineProperty

我们通常可以对进行输入框进行数据的监听,只需要用到了input 事件或 change事件,就可以实时监听到数据的改变,但是如果只是一个单独的数据呢?怎么去做监听,watch吗??哈哈。

所以 vue响应式就用到了object.defineProperty 中的 get 和 set 方法 ,如果对方法不了解可访问蓝色文字。简单来说 只要一访问就会触发get,设置就会触发set。

基本语法:

Object.defineProperty(对象,键,{
        get (   )   {   },
        set (val) {   }        
})

 let data = {
     name:'奥特曼'
 }

 Object.defineProperty(data,'name',{
       get(){
         console.log('访问了')
       },
       set(val){
        console.log('设置了,值是:',val)
      }
  })

1. 单个数据实现响应

实现效果:

为了和vue保持格式一致 我们先定义初始变量data ,并且一开始把值赋给类名为name的内容数据

<div class="name"></div>
<script>
     let data = {
       name:'奥特曼'
    }

   function setName() {
       document.querySelector('.name').innerHTML = username
    }

    setName() 
 </script>

接下来要对data.name进行实时的监听,就要用到了obj.defineProperty

     let username = "奥特曼";
      Object.defineProperty(data, "name", {
        get() {
          console.log("访问了");
          return username;
        },
        set(val) {
          console.log("设置了,值是:", val);
          username = val;
          setName();
        },
      });

这里注意 特意用了一个中间变量 username,如果不这么用你可能会想到,错误写法别抄哦

      get(){
              console.log('访问了');
              return data.name
           },

为什么不直接把data.username给返回出去,为什么要返回一个值一样的username?原因就是 我们返回着data.name 其实也是在访问他,然后呢每次访问每次进入get函数 就会进入一个死循环。

2.多个数据实现响应式

这里就不过多解释了 只需要把对象循环一下 利用Object.defineProperty监听每个属性,我相信你可以看懂的

<script>    
    let data = {
        username:'奥特曼',
        age:18,
    }

    function setData() {
        username.innerHTML = data.username
        age.innerHTML = data.age
    }

    function observe(data) {
        for (const key in data) {
            let value = data[key]
            Object.defineProperty(data,key,{
                get(){
                    return value 
                },
                set(val){
                    value = val
                    setData()
                }
            })
        }
    }

    observe(data)
    setData()

</script>

3. 监听复杂数据类型响应式

我们只需要判断当前的参数是否是对象 如果是对象利用一下递归。

<script>    

    let data = {
        username:'奥特曼',
        age:18,
        student:{
            name :'怪兽'
        }
    }

    function setData() {
        username.innerHTML = data.username
        age.innerHTML = data.age
        monster.innerHTML = data.student.name
    }

    function observe(data) {
        for (const key in data) {
            if(typeof data[key] == 'object') {
               observe(data[key])
            }
            let value = data[key]
            Object.defineProperty(data,key,{
                get(){
                    return value 
                },
                set(val){
                    value = val
                    setData()
                }
            })
        }
    }

    observe(data)
    setData()

</script>

4.新增对象属性和数组下标修改

在vue中,我们是检测不到一个对象新增属性和直接修改数组某一项的变化,但是上面的代码中是能够对数组下标进行修改的,那为什么vue不可以呢?

 尤大大也说考虑到了性能和用户体验的问题 如果一个数组10000条数据 监听这每一项的数据变化 确实也有很大的性能问题,但vue也提供了解决方案 $set

贴一下 修改数组下标 及 修改不了新增的对象属性代码

<script>    
    let data = {
        username:'奥特曼',
        age:18,
        student:{
            name :'怪兽'
        },
        arr:[0,1,2,3]
    }

    function setData() {
        username.innerHTML = data.username
        age.innerHTML = data.age
        monster.innerHTML = data.student.name
        // 无法对新增的属性进行监听  原因就是observe  一开始就对原数据进行数据的监听  这也是object.defineproperty的本身缺陷
        monsterAge.innerHTML = data.student.age
        number.innerHTML = data.arr[0]
    }

    function observe(data) {
        for (const key in data) {
            if(typeof data[key] == 'object') {
                observe(data[key])
            }
            let value = data[key]
            Object.defineProperty(data,key,{
                get(){
                    return value 
                },
                set(val){
                    value = val
                    setData()
                }
            })
        }
    }

    observe(data)
    setData()

</script>

补充:但是有一点哈,有时候呢 你是可以修改数组某一项实现响应式的,什么时候呢看下面的例子

    <div>
        <div> {
   
   {arr[0]}}</div>
        {
   
   { obj.a }}
        <button @click="editNumber">要修改了</button>
    </div>

<script>
export default {
  data () {
    return {
      arr: [0, 1, 2, 3, 4, 5],
      obj: { a: 1 }
    }
  },
  methods: {
    editNumber () {
      this.arr[0] = 999
      // 如果不加下面这一行代码,视图就不会更新
      // 更新的原因:下面的数据是响应式的数据他会去更新视图,一旦更新视图 数据是对整个组件进行更新的,所以arr[0] 会更新
      // 其实底层的object.defineProperty 可以对数组进行更新 但是尤大考虑到数组 的性能与用户体验不成正比 去掉了对数组的响应式 (获取涉及几万条数组非常的大)
      this.obj.a = 2
    }
  }
}
</script>

猜你喜欢

转载自blog.csdn.net/m0_46846526/article/details/128808952
今日推荐