vue-数据监听与依赖收集

27 篇文章 3 订阅
5 篇文章 0 订阅

文章围绕下面demo进行分析

<div id="app">
    <span>{{a.b}} {{c}} {{d}}</span>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: function(){
            return {
                a: {
                    b: 1
                },
                c: 1
            }
        },
        watch:{
          'a.b': function(){
            console.log(22)
          }
        },
        computed:{
          d: function (){
            return this.c
          }
        }
    });
</script>
数据监听:从initData开始

vue监听data数据的步骤可以概括为下面几步:

1、使用initData初始化data数据

2、将data挂载到vm._data中(后面会将_data赋值给$data,这里的data如果是函数,就是返回的数据)

3、通过observe监听数据

4、如果数据是一个非object类型的数据(typeof == object,且不为null),终止程序

5、observe中使用new Observer生成ob

6、Observer中使用`this.dep = new Dep()`挂载dep

7、Observer中将__ob__指向this,所以可以使用`__ob__.dep`找到dep

8、遍历属性,使用defineReactive监听属性

9、defineReactive中生成`var dep = new Dep();`,这个dep是一个闭包

10、defineReactive中使用observe监听属性所代表的值,也就是步骤3,至此循环递归
依赖收集

三种watcher

1、normal-watcher(watch中的数据,通过initWatch生成) 记录在_watchers中(所有的watch都会存放在这里)

2、computed-watcher(computed) 记录在_computedWatchers中

3、render-watcher 就是vm._watcher
normal-watcher:运行initWatch

我们在组件钩子函数watch 中定义的,都属于这种类型,即只要监听的属性改变了,都会触发定义好的回调函数,这类watch的expression是计算属性中的属性名。

在初始化watch的时候(initWatch),会调用vm. w a t c h 函 数 , v m . watch函数,vm. watchvm.watch函数会直接使用Watcher构建观察者对象。watch中属性的值作为watcher.cb存在,在观察者update的时候,在watcher.run函数中执行。watch中属性的key会进行parsePath处理,并用parsePath返回的函数,获取watch的初始值value。

比如把a.b解析为监听a中的b属性,这样会先寻找a,也就是触发a的get。

1、赋值cb为a.b的值,赋值expression为a.b

2、使用parsePath解析expOrFn,即a.b,并将返回的函数赋值给该watcher实例的getter即this.getter

3、运行this.get获取a.b的值,进行依赖收集,this指向a.b的 watcher实例

4、运行pushTarget将Dep.target指向该watcher实例

5、运行this.getter,会先获取a,运行defineReactive中的get

6、运行dep.depend(此时的dep指的是data.a的dep,在闭包中),进而运行Dep.target.addDep,将data.a的dep追加进该watcher实例中,并将该watcher实例追加进data.a的dep.subs中,因为a具有__ob__,所以会运行a.__ob__.dep.depend,将a的dep追加进该watcher实例中,并将该watcher实例追加进a的dep.subs中

7、利用获取到的a去获取属性b

8、运行dep.depend(此时的dep指的是a.b的dep,在闭包中),进而运行Dep.target.addDep,将a.b的dep追加进该watcher实例中,并将该watcher实例追加进a.b的dep.subs中,因为b不具有__ob__,所以不会继续追加

9、到这里就获取到了a.b的值1,并将这个值赋值给该watcher实例的value
computed-watcher:运行initComputed

我们在组件钩子函数computed中定义的,都属于这种类型,每一个 computed 属性,最后都会生成一个对应的 watcher 对象,但是这类 watcher 有个特点:当计算属性依赖于其他数据时,属性并不会立即重新计算,只有之后其他地方需要读取属性的时候,它才会真正计算,即具备 lazy(懒计算)特性。这类watch的expression是计算属性中的属性名。

在初始化computed的时候(initComputed),会先生成watch实例,然后监测数据是否已经存在data或props上,如果存在则抛出警告,否则调用defineComputed函数,监听数据,为组件中的属性绑定getter及setter。

**注意:**computed中的属性是直接绑定在vm上的,所以如果写a.d,那就是属性名是a.d,而不是a对象的属性d。

1、执行initComputed,遍历computed生成watch实例,并挂载到vm._computedWatchers上

    (1)赋值cb为空函数,赋值expression为expOrFn(d的值,函数或对象的get)的字符串形式,赋值this.getter为expOrFn

    (2)默认的computed设置lazy为true,不运行this.get获取值,所以到这里watch实例就生成了。

2、执行defineComputed函数,如果d的值是函数,或者d的cache属性不是false,那么会使用createComputedGetter函数生成computedGetter函数,作为d的getter函数,如果cache设置为false,不经过createComputedGetter封装,每次获取都会运行get,而d的setter就是他的set或者空函数(默认)

3、当获取d的值时(比如渲染,此时Dep.target为渲染watcher),会运行computedGetter函数

4、根据watcher.dirty的值决定是否运行watcher.evaluate重新获取属性值,这是懒计算的关键。dirty的值默认为true,在依赖改变时或update时变为true,在evaluate后变为false

    (1)watcher.evaluate中运行this.get获取d的值,进行依赖收集,this指向d的 watcher实例

    (2)运行pushTarget将Dep.target指向d的watcher实例

    (3)运行this.getter,会先获取this.c的值,运行defineReactive中的get

    (4)运行dep.depend(此时的dep指的是data.c的dep,在闭包中),进而运行Dep.target.addDep,将data.c的dep追加进d的watcher实例中,并将d的watcher实例追加进data.c的dep.subs中

    (5)d的watcher出栈,将Dep.target重新设置为渲染watcher

5、运行watcher.depend,遍历watcher.deps(这里主要是data.c的dep),将他们与渲染watcher互相关联

**注意:**computed中的数据不经过Observer监听,所以不存在dep

render-watcher:运行mountComponent挂载组件

每一个组件都会有一个 render-watcher, 当 data/computed 中的属性改变的时候,会调用该 render-watcher 来更新组件的视图。这类watch的expression是 function () {vm._update(vm._render(), hydrating);}

1、生成updateComponent函数,

2、实例化一个渲染watcher,把updateComponent当作expOrFn参数传入

3、赋值cb为空函数,赋值expression为updateComponent的字符串形式,赋值this.getter为expOrFn

4、运行this.get,进行依赖收集

5、运行pushTarget将Dep.target指向该渲染watcher实例

6、运行this.getter,即updateComponent函数

7、用render函数生成vnode,并将其作为第一个参数,传入_update

8、render函数中会对用到的变量进行getter操作,并完成依赖收集

    (1)获取a,将data.a的dep追加进该渲染watcher实例中,并将该渲染watcher实例追加进data.a的dep.subs中

    (2)获取a.b,将a.b的dep追加进该渲染watcher实例中,并将该渲染watcher实例追加进a.b的dep.subs中

    (3)获取c,将data.c的dep追加进该渲染watcher实例中,并将该渲染watcher实例追加进data.c的dep.subs中

    (4)获取d,运行d的getter函数computedGetter(详情看上面computed-watcher中的步骤3-5)

9、完成依赖收集后,变量修改,会触发dep.notify,通知渲染watcher实例的update操作,重新进行渲染
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 监听Vue数据是指通过Vue提供的监听方法,可以实时监测到数据的变化并做出相应的操作。在Vue中,我们可以使用watch来监听数据的变化。 通过在Vue实例中使用watch属性,我们可以将要监听数据以字符串形式传递给watch,并在watch中定义一个函数,当数据发生变化时,该函数就会被触发。 例如,假设我们要监听一个叫做"count"的数据,可以在Vue实例中添加如下代码: ``` watch: { count(newValue, oldValue) { console.log('count的值发生变化啦!新的值为:' + newValue + ',旧的值为:' + oldValue); // 可以在这里执行一些自定义的操作 } } ``` 在上述代码中,我们在watch属性中定义了一个count函数,当count数据发生变化时,该函数会被触发。在函数体中,我们可以获取到变化后的新值和变化前的旧值,并可以在这里执行一些自定义的操作。 监听Vue数据可以帮助我们实时获取数据的变化情况,以便及时做出响应。这对于一些需要实时更新数据的场景非常有用,比如当数据发生变化时,我们需要根据新的数据进行计算、展示等操作。 总之,通过监听Vue数据,我们可以在数据变化时得到通知,并进行相应的处理,从而实现数据的实时更新及操作。 ### 回答2: Vue是一种用于构建用户界面的渐进式JavaScript框架。它通过数据驱动和组件化的方式使得开发者可以简单、高效地构建可复用的UI组件。Vue数据监听机制是其核心特性之一。 Vue通过采用响应式的数据绑定机制来监听数据的变化。当一个数据被绑定到Vue实例中的属性时,Vue会将这个属性转化为getter/setter,并且在需要的时候收集依赖和触发更新。这个机制可以让Vue追踪到每个属性的依赖关系,并在属性发生变化时自动更新有关联的组件。 Vue实现数据监听的方式主要有两种:Object.defineProperty和Proxy。在较低版本的浏览器中,Vue使用Object.defineProperty来实现数据监听。它通过重写对象属性的getter和setter来实现依赖追踪和更新通知。在较新版本的浏览器中,Vue使用Proxy来实现数据监听。Proxy可以劫持整个对象,不需要像Object.defineProperty那样重写getter和setter。 对于Vue来说,数据监听是非常重要的,它可以让开发者编写的代码更具有可维护性和可复用性。当数据发生变化时,Vue会自动检测到这些变化并更新相关的组件,从而实现了数据和视图的双向绑定。这种自动化的数据监听机制可以极大地减少开发者的工作量,提高开发效率。 以一个简单示例来说明数据监听的实现方式。假设有一个Vue实例: ```javascript var vm = new Vue({ data: { message: 'Hello Vue!' } }) ``` 当我们修改`data`中的`message`属性时,例如: ```javascript vm.message = 'Hello World!' ``` Vue会自动检测到`message`属性的变化,并更新对应的组件。在这个示例中,Vue会将`message`属性转化为getter/setter,并在需要的时候触发组件的更新操作,使得界面中显示的内容变为新的值。 综上所述,Vue数据监听机制是通过响应式的数据绑定方式来实现的,它是Vue框架的核心特性之一,能够实现数据和视图的自动更新,提高开发效率和减少工作量。 ### 回答3: Vue 是一种用于构建用户界面的渐进式JavaScript框架。它包含了一系列的工具和库,使开发人员能够轻松地构建复杂的单页应用程序。Vue 提供了一种数据监听的机制,可以实时地追踪和更新数据的变化。 Vue数据监听是通过Vue实例中的数据属性来实现的。当数据发生变化时,Vue会自动检测到变化并更新相应的视图。这种监听机制可以确保视图与数据的同步,使开发者能够更加便捷地操作数据和界面。 Vue提供了多种监听数据变化的方式。最常见的方式是使用`v-model`指令将数据绑定到表单元素上,当表单数据发生变化时,Vue会自动更新与之绑定的数据属性。此外,Vue还提供了`watch`属性,可以监听指定数据的变化并执行相应的回调函数。通过`computed`属性,Vue还可以创建计算属性,实时计算数据依赖关系。 除了上述常用方式外,Vue还提供了更高级的数据监听功能。开发者可以使用`$watch`方法手动监听数据的变化。使用该方法,可以监听具体的属性变化,也可以监听整个数据对象的变化。这种方式可以更加灵活地对数据进行监听和操作。 总而言之,Vue提供了灵活而强大的数据监听功能,使开发者能够方便地追踪和处理数据的变化。这为开发人员提供了更好的开发体验和更快速的应用程序开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值