当前位置:   article > 正文

vue数据检测原理

vue数据检测原理

前言
Vue中的数据监听离不开Object.defineProperty()方法的使用,在了解数据监测原理之前,建议先掌握defineProperty的用法。
目标

1 数据监测问题
2 数据监测原理
3 如何实现数组更新

1 遇到的问题

数组更新问题

<button @click="updatePeople">更新一个用户信息</button>
<ul>
   <li v-for="(item,index) in people" :key="index">
      {{item.name}}----{{item.age}}
   </li>
</ul>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
// 可以实时更新
updatePeople(){
     console.log('更新用户信息')
     this.people[0].name = '马冬梅'
     this.people[0].age = '40'
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

updatePeople(){
     console.log('更新用户信息')
     // 实时更新页面失败
     this.people[0] = {name:'马冬梅',age:40}
},
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述
vue中的数据更新主要通过Object.defineProperty()中的set来实现的,people数组下的对象没有get与set,而对象中的name、age有set,所以在设置name、age值时会同步的进行更新
在这里插入图片描述

Vue.set()

现有一个需求:在页面渲染完成后,动态的给对象添加属性,并打印属性与属性值。
看似很好实现的一个需求,但是当我们的动态的添加属性后,也页面却无任何更新,这是为什么呢?
给data中的属性绑定get、set是在new Vue()的过程中进行绑定的,但是动态添加属性是在绑定之后,也就是后来添加的属性无set,修改值就无法试试的去监测数据更新了。
在这里插入图片描述
为了解决此问题,Vue提供了Vue.set方法,用于添加响应式的property
Vue.set() 与 vm.$set()时一样的效果
Vue.set(vm.pseron,'sex','男生') === vm. $set(vm.pseron,'sex','男生')
Vue.set()也不是任何情况下都可以使用的,若作用的对象是Vue实例或者实例的根数组对象,会无效
在这里插入图片描述

data:{
  pserson: {
        name: "李四",
        age: 32,
        children: {
          name: "王五",
          age: 6,
        },
      }
 }
<ul>
    <li v-for="(value,key,index) of pserson" :key="index">
       {{key}}----------{{value}}
    </li>
</ul>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述

2 Vue检测数据原理

1 对象

在讨论如何解决数组更新问题之前,先来看一下对象是如何实现实时更新的。
详细的就不再描述了,不了解的可以去看看vue 【vue中的数据代理】
对象代理流程大致是:

加工
触发
set
data中的数据
vm._data
修改data.name
页面更新

简单写个例子来模拟一下Vue中对象的数据监听。Vue中对象的数据监听用的也是Object.defineProperty,通过递归遍历对象,确保对象中的每个属性值都有get与set

<script type="text/javascript">
  let data = {
    name: '张三',
    age: '18'
  }
  const obs = new Observer(data)
  let vm = {}
  vm._data = data = obs
  function Observer(obj) {
    const keys = Object.keys(obj)
    keys.forEach(key => {
      Object.defineProperty(this, key, {
        get() {
          return obj[key]
        },
        set(val) {
          obj[key] = val
        }
      })
    });
  }
  </script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这里插入图片描述
在这里插入图片描述

Vue.set()

现有一个需求:在页面渲染完成后,动态的给对象添加属性,并打印属性与属性值。
看似很好实现的一个需求,但是当我们的动态的添加属性后,也页面却无任何更新,这是为什么呢?
给data中的属性绑定get、set是在new Vue()的过程中进行绑定的,但是动态添加属性是在绑定之后,也就是后来添加的属性无set,修改值就无法试试的去监测数据更新了。
在这里插入图片描述

data:{
  pserson: {
        name: "李四",
        age: 32,
        children: {
          name: "王五",
          age: 6,
        },
      }
 }
<ul>
    <li v-for="(value,key,index) of pserson" :key="index">
       {{key}}----------{{value}}
    </li>
</ul>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述

  • 如何监测对象中的数据?
    通过setter实现监视,且要在new Vue时就传入要监测的数据。
    (1).对象中后追加的属性,Vue默认不做响应式处理
    (2).如需给后添加的属性做响应式,请使用如下API:
    • Vue.set(target,propertyName/index, value) 或 vm.$set(target,propertyName/index, value)

2 数组

当数组中对象的属性发生变化时,属性可以实时的监听。但是我们整个改变数组的中的值时,页面却没有实时更新。
在这里插入图片描述
我们用数组方法往数组中添加对象,这个对象中的属性也是响应式的

  • 如何监测数组中的数据?
    通过包裹数组更新元素的方法实现,本质就是做了两件事:
    • (1).调用原生对应的方法对数组进行更新。
    • (2).重新解析模板,进而更新页面。
  • 在vue修改数组中的某个元素一定要用如下方法:
    • 1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()。用如下方法向数组中添加对象,对象中的属性也是响应式
    • 2.Vue.set()或 vm.$set()
  • 特别注意: Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添属性!!!
    在这里插入图片描述
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/428654
推荐阅读
相关标签
  

闽ICP备14008679号