3

19_Vue如何监测到对象类型数据发生改变的? - 澜璨

 1 year ago
source link: https://www.cnblogs.com/wavesbright/p/16851727.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
  • 我们之前讲过,我们在data当中配置的属性,最终会挂载在vue实例身上,而data这个配置项,最终也会在vue身上成为一个新的属性 == _data
    • image-20221029174302808
  • 当我们在页面DOM当中,去使用data当中的属性的时候,属性值发生变化,页面是不是会自动更新? 为什么会这样?
  • 你可以理解为 Vue底层默认有一个监视器,负责监视这些属性的变化
  • watchcomputed不同,这个监视是全局的,watch与computed是针对单独的,或者一些属性

不过目前可以说一句,watch与vue底层监视,用的是一套类似的逻辑

检测数据的原理

这个概念是非常重要的,所以这节课是不能跳过的,否则有一天会为这个行为买单(谢谢,已经买过了)

我们先来做个需求吧,这个需求不演示不行

  1. 你写一段代码,这个代码你需要修改data当中的数据
  2. 修改数据的行为,不能被vue检测到,也就是卡bug。
  3. 请你实现这个功能

这是我的html设计,ul 当中的li标签渲染data当中persons这个数组的数据

image-20221101164407586
image-20221101164444632

button按钮呢,设置了一个点击事件,这个点击事件用来单独修改 马冬梅这个对象的信息

image-20221101164505759

可以看到,在这种赋值的情况下,我们成功的对 马冬梅 进行了修改数据

并且在vue当中也能检测到

11-1-2

卡bug,引出问题

既然是 对马冬梅进行修改,我们换一种方式来对他进行修改

11-1-3

为什么这次数据修改不成功了,这是为什么?

  • 当我点击这个按钮的时候,在内存当中,persons[0]的数据确实发生改变了
  • 但是,这次修改并没有被vue所检测到
  • 至于控制台的数据到底修补修改,取决于你什么时候打开开发者工具
image-20221101165614093

vue是如何检测对象数据改变的

  • 我们先回顾一下关于vue的数据监测,详细博文
  • 我现在data这里有一个属性name和属性persons
    • image-20221101165925946
  • 打开控制台,在vue实例身上也有这俩属性
    • image-20221101170017797
  • 我们都知道,为什么这俩data当中属性会出现在vue实例身上,是因为做了数据代理
  • 在vue身上有个_data,这个下划线data当中包含着我们上图配置的data的所有数据,并且还对这个配置项data做了加工
    • image-20221101170237817
  • 因为如果只是 将 data的值,赋给_data,那么二者的内容应该是相等的才是
  • 但是现在显然不是,说明这里做了加工
  • 为啥他要加工?
    • 它加工了就可以做响应式了

关于definedproperty

  • 之前说过,vue的数据代理definedProperty 这个API有关
  • 那么其内部是如何进行数据代理的呢?
  • 如果不使用 vue框架,我们能实现数据代理吗?
  • 我们来测试一下
  • 按照正常的理解,如果我们需要对age这个属性进行数据代理
  • 让页面能够检测到数据的改变,那么就需要使用这个接口(defined......)
  • 那么这个接口的调用,需要如下几个配置
    • 要给谁添加属性
    • 属性名是什么
    • 配置项(getter和setter)
  • 那么对getter而言,如果该属性被访问到了,那么就需要返回该属性的值
    • image-20221102101919433
  • 对setter而言,当属性值,发生修改,那么将接收到的修改的属性值,重新赋值给该属性
image-20221102101738131

我们虽然添加的是age,但是这里的意思是将原有属性age覆盖掉,使用这个新的age

我们来看下测试结果

11-2-1

出现bug的原因

  • 其实这个问题很好理解,我们看下错误原因
    • image-20221102102329508
  • 这是一个 无限递归产生的bug,该方法一直无限的被调用,从而产生了这个错误
  • 为什么呢?
  • 我们仔细看下这段代码
    1. image-20221102102652200
    2. 当,age属性被访问的时候,会调用get函数
    3. 调用get函数,会返回age
    4. 返回的过程当中,age是不是又被访问了
    5. 从而产生死循环,无限递归
  • 为什么无法修改属性呢?也是这个道理

所以,vue底层的数据代理,或者说数据加工没有我们想的这么简单,那么人家是怎么实现的呢

Observer

  • 在vue当中,有个接口叫做Observer,这个接口用来监视页面数据发生的变化
  • 不过他底层是如何进行监听的呢
  • 我们写不到底层那么详细,只写主要的部分

1、首先我们准备一个data,这里面存放了两个属性,name和age

image-20221102112252052

2、我们创建一个function ==> Observer

image-20221102112336622

然后实例化这个 Observer,js当中,function是可以当做构造函数使用的

image-20221102112446513

该函数需要一个属性,从参数名可以看出,这是一个对象属性

3、现在我们就来配置这个对象,首先我们需要获取到 data这个对象当中的所有key值

image-20221102112642593

4、对这个数组,进行循环

image-20221102112734575

5、在迭代的过程当中,使用definedProperty进行数据代理

image-20221102112845830

参数解析,为什么这里,添加数据的对象(参数1) 是 this

  1. 使用this,那么就是给 this所指向的对象 ==> Observer;也就是我们刚刚实例化出来的对象
    • image-20221102113338407
  2. 给它添加属性(property参数
  3. 那么接下来我们就在 参数三 当中配置get和set了

6、get和set

image-20221102113208304

数组当中是可以用字符串来获取元素值的(很少)

完整代码

// 这有一个对象,对象有两个属性
    let data = {
        name: "waves",
        age: 0
    }

    // 实例化一个监视器对象
    let observer = new Observer(data);

    // 监视对象Observer
    function Observer(obj){
        // 1、获取data当中的所有key值
        let properties = Object.keys(data); // ["name","age"]

        // 2、迭代 properties数组
        properties.forEach((property)=>{
            // 3、在迭代的过程当中,使用definedProperty进行数据代理
            Object.defineProperty(this,property,{
                // 配置get和set
                get(){
                    // 很简单,因为data没有做数据代理,返回data[property]即可
                    return data[property]; // data["name"] = waves
                },
                set(val){
                    // 赋值即可
                    data[property] = val
                }
            })
        })
    }
  1. 我们这里设置了一个data
    • image-20221102115237706
  2. 通过我们的一系列配置,data身上有的属性,Observer实例身上也有
  3. 并且,这个observer身上的属性都做了数据代理
  4. 当然,vue写的比我们完善的多
  5. 比如,如果data当中还存在对象怎么办?
image-20221102115801541

vue在这里写了递归,一直找,找到这个属性不再是对象为止

image-20221102120105239

数组也是一个道理,vue也能给你找出来,不过 关于数组和对象的代理,这二者的处理方式不同,下节会讲解


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK