前端Vue篇之Vue是如何收集依赖的?

这篇具有很好参考价值的文章主要介绍了前端Vue篇之Vue是如何收集依赖的?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


Vue是如何收集依赖的?

在 Vue 中,依赖收集是一个重要的概念,它是 Vue 实现响应式数据的核心。当一个组件被初始化时,Vue 会对组件的 data 进行初始化,将普通的 JavaScript 对象变成响应式对象。在这个过程中,Vue 会进行依赖收集,以便在数据发生变化时,能够通知到所有依赖这个数据的地方。

依赖收集的过程主要涉及到三个类:DepWatcherVue

1. Dep 类

Dep 是依赖收集的核心,它的主要作用是管理所有的 WatcherDep 类中有一个静态属性 target,它指向当前正在计算的 Watcher,保证了同一时间全局只有一个 Watcher 被计算。Dep 类中还有一个 subs 属性,它是一个 Watcher 的数组,用来存储所有依赖这个 DepWatcher

1. 静态属性 target

Dep 类中有一个静态属性 target。这个属性的作用是指向当前正在计算的 Watcher,它的存在保证了在同一时间内全局只有一个 Watcher 被计算。你可以把它想象成一个焦点,告诉系统当前需要关注哪个 Watcher

2. subs 属性

另一个属性是 subs,它是一个存储 Watcher 的数组。这意味着 Dep 类实际上就是对 Watcher 的管理者。当数据发生变化时,Dep 就会通知所有依赖于它的 Watcher 进行更新,而这些 Watcher 则会负责相应的视图更新。

3. 方法:addSub 和 removeSub

addSub 方法用于将 Watcher 添加到 subs 数组中,而 removeSub 方法则是用来从 subs 数组中移除对应的 Watcher

4. 方法:depend 和 notify

  • depend 方法的作用是在计算属性或者渲染过程中建立依赖关系。如果当前存在正在计算的 Watcher(即 Dep.target 存在),那么就会将当前的 Dep 与该 Watcher 建立关联。
  • notify 方法则是在数据发生变化时通知所有依赖这个 DepWatcher 执行更新操作。它遍历 subs 数组中的所有 Watcher,并逐一触发它们的更新方法。

在实际工作项目中,Dep 类的概念对于理解 Vue.js 的响应式原理和数据双向绑定机制至关重要。在大型前端应用中,了解依赖收集的过程以及如何管理依赖关系是非常有益的,尤其是在构建自定义组件或处理复杂的数据流时。

案例需求

假设有一个用户界面,其中包含一个数字输入框和一个显示框。输入框中的值会影响显示框中的内容。我们希望在输入框的值改变时,显示框能够自动更新。

class Dep {
  constructor() {
    this.subs = []; // 存储所有依赖这个Dep的Watcher
  }

  depend() {
    if (Dep.target) {
      Dep.target.addDep(this); // 将当前Dep与正在计算的Watcher关联起来
    }
  }

  notify() {
    this.subs.forEach(watcher => {
      watcher.update(); // 通知所有依赖这个Dep的Watcher进行更新
    });
  }
}

Dep.target = null; // 全局的当前正在计算的Watcher

class Watcher {
  constructor() {
    Dep.target = this;
  }

  addDep(dep) {
    dep.subs.push(this); // 将当前Watcher加入到Dep的subs数组中
  }

  update() {
    // 执行更新操作
  }
}

// 示例用法
let dep = new Dep();
let watcher = new Watcher();
dep.depend(); // 将当前Dep与正在计算的Watcher关联起来
dep.notify(); // 通知所有依赖这个Dep的Watcher进行更新
  1. 创建Dep类,其中包括subs数组和depend、notify方法。
  2. 创建Watcher类,其中包括addDep和update方法。
  3. 在Dep类中,通过target属性指向当前正在计算的Watcher,在depend方法中将当前Dep与正在计算的Watcher关联起来,在notify方法中通知所有依赖这个Dep的Watcher进行更新。
  4. 在Watcher类中,通过addDep方法将当前Watcher加入到Dep的subs数组中,在update方法中执行更新操作。
  • Dep类和Watcher类是数据响应式系统的核心,理解其原理对于理解Vue等前端框架的工作原理非常重要。
  • 在实际项目中,可以根据具体需求对Dep类和Watcher类进行定制和扩展,以满足不同的业务场景需求。

案例需求

假设我们有一个需求,希望在用户修改某个输入框的数值时,页面上的其他相关部分能够实时更新。这就需要利用 Vue.js 的响应式系统来实现数据的自动更新。在这种情况下,理解 Dep 类的作用将有助于我们更好地设计数据流和组件通信。

<template>
  <div>
    <input v-model="value" @input="updateOtherSections" />
    <div>{{ calculatedValue }}</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: 0,
      calculatedValue: 0
    };
  },
  mounted() {
    this.$watch(
      () => this.value,
      () => {
        this.calculatedValue = this.value * 2; // 示例:当输入框数值改变时触发更新
      }
    );
  },
  methods: {
    updateOtherSections() {
      // 更新其他相关部分的逻辑
    }
  }
};
</script>
  1. mounted 钩子中,通过 this.$watch 监听 value 的变化。
  2. value 变化时,会触发相应的更新函数,计算新的值并更新到 calculatedValue
  3. 用户输入框的值变化会引起 value 的变化,从而触发 calculatedValue 的更新。

总结

Dep 类通过管理依赖关系,用于管理所有的Watcher,确保了数据变化时相关的视图能够得到更新。它利用 subs 数组存储依赖它的 Watcher,并通过 notify 方法通知它们进行更新。同时,使用静态属性 target 确保了在同一时间内只有一个全局的 Watcher 被计算。通过理解 Dep 类的作用,我们可以更好地设计和构建具有复杂数据流的 Vue 组件,并更好地应对实际项目中的需求。

2. Watcher 类

Watcher 是一个用来计算表达式的类。在 Watcher 的构造函数中,它会执行表达式,这个表达式可能会触发数据的 getter,从而进行依赖收集。Watcher 类中还有一个 addDep 方法,它会将当前的 Watcher 添加到 Depsubs 数组中。

class Watcher {
  getter;
  ...
  constructor (vm, expression){
    ...
    this.getter = expression;
    this.get();
  }
  get () {
    pushTarget(this);
    value = this.getter.call(vm, vm)
    ...
    return value
  }
  addDep (dep){
        ...
    dep.addSub(this)
  }
  ...
}
function pushTarget (_target) {
  Dep.target = _target
}

构造函数

Watcher 类有一个构造函数,它接受两个参数:vmexpression。在构造函数中,将传入的 expression 赋值给 getter 属性,并立即调用 get 方法。

get 方法

  • get 方法是 Watcher 类中最关键的方法之一。当 Watcher 被创建时,会立即调用 get 方法。
  • get 方法内部,会将当前的 Watcher 推入一个全局的位置(通过 pushTarget 函数),然后执行 expression,这个 expression 可能是一个函数或者计算属性的表达式。
  • 在执行过程中,会触发对应数据的 getter,从而建立起依赖关系,并且触发了依赖收集过程。

addDep 方法

  • addDep 方法用于将当前的 Watcher 添加到指定的 Dep 实例中,建立起 WatcherDep 之间的关联。
  • 这样,在数据变化时,Dep 就能够通知到相应的 Watcher 进行更新操作。

pushTarget 函数

pushTarget 函数的作用是将当前的 Watcher 设置为全局唯一的 Dep.target,以确保在同一时间内全局只有一个 Watcher 被计算。

  • get 方法中,通过调用 expression 来触发数据的 getter,从而建立起依赖关系。
  • 使用 addDep 方法将当前的 Watcher 添加到对应的 Dep 实例中,确保在数据变化时能够及时通知到相关的 Watcher 进行更新操作。

总结

Watcher 类通过 get 方法建立了依赖关系,并且在初始化时会立即执行 expression,从而触发对应数据的 getter,进而进行依赖收集。通过 addDep 方法,WatcherDep 建立了关联,确保了数据变化时能够及时通知到相关的 Watcher 进行更新操作。

3. Vue 类

Vue 类是 Vue 的入口,它的主要作用是初始化 Vue 应用。在 Vue 类的初始化过程中,会对组件的 data 进行初始化,将普通的 JavaScript 对象变成响应式对象。在这个过程中,会进行依赖收集。

依赖收集的过程如下:

  1. 首先,Vue 会对组件的 data 进行初始化,将普通的 JavaScript 对象变成响应式对象。

  2. 然后,Vue 会实例化一个 Watcher,并执行 Watcherget 方法。

  3. get 方法中,Watcher 会执行表达式,这个表达式可能会触发数据的 getter,从而进行依赖收集。

  4. getter 中,会调用 Dep.target.addDep(this),将当前的 Watcher 添加到数据的 Depsubs 数组中。

  5. 这样,当数据发生变化时,Dep 就可以通过 subs 数组,找到所有依赖这个数据的 Watcher,并通知它们数据发生了变化。

这就是 Vue 如何进行依赖收集的过程。

updateComponent = () => {
  vm._update(vm._render())
}
new Watcher(vm, updateComponent)

updateComponent 函数

updateComponent 函数是一个箭头函数,它的作用是更新 Vue 实例的视图。在这个函数内部,它调用了 vm._render() 方法生成虚拟 DOM,并将其传递给 vm._update() 方法来更新实际的 DOM。

创建 Watcher

通过 new Watcher(vm, updateComponent) 创建了一个新的 Watcher 实例。这里的 vm 是 Vue 实例,updateComponent 是上面定义的更新函数。

在创建 Watcher 实例时,会立即执行 updateComponent 函数,这样就建立了依赖关系,updateComponent 函数中所使用的数据发生变化时,对应的 Watcher 就能够收到通知,并触发更新操作。

  • 当创建 Watcher 实例时,会立即执行 updateComponent 函数,从而进行依赖收集并建立起对应的关联。
  • updateComponent 函数的执行将触发 Vue 实例的重新渲染过程,确保视图能够及时地响应数据的变化。

总结

通过创建 Watcher 实例,将 updateComponent 函数与 Vue 实例建立了关联,确保了当相关数据发生变化时,能够触发视图的更新操作。这种机制保证了 Vue 的响应式系统能够自动追踪数据的变化,并及时地更新视图,从而实现了数据驱动视图的效果。

持续学习总结记录中,回顾一下上面的内容:
Vue通过在数据属性的getter中收集依赖。当一个数据被访问时,Watcher会被添加到依赖列表中。这样,当数据变化时,Watcher就能够得到通知,并进行相应的更新操作,从而确保视图能够及时地反映数据的变化。文章来源地址https://www.toymoban.com/news/detail-849150.html

到了这里,关于前端Vue篇之Vue是如何收集依赖的?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端Vue篇之 Vue的基本原理

    Vue.js 是一个流行的 JavaScript 框架,用于构建用户界面和单页面应用。其基本原理包括: 响应式数据 :Vue 的核心是响应式数据系统。在创建 Vue 实例时,Vue会遍历data对象中的所有属性,并使用Object.defineProperty(或在Vue 3.0中使用Proxy)将它们转换为getter/setter。这些getter/setter在

    2024年02月19日
    浏览(34)
  • Vue2依赖收集原理(Dep、Watcher、Observer)

    观察者模式定义了对象间一对多的依赖关系。即被观察者状态发生变动时,所有依赖于它的观察者都会得到通知并自动更新。解决了主体对象和观察者之间功能的耦合。 Vue中基于 Observer、Dep、Watcher 三个类实现了观察者模式 Observer类 负责数据劫持,访问数据时,调用 dep.dep

    2023年04月10日
    浏览(34)
  • 前端Vue篇之Vue3响应式:Ref和Reactive

    在Vue3中,响应式编程是非常重要的概念,其中 Ref 和 Reactive 是两个关键的API。 Ref : Ref 用于创建一个响应式的基本数据类型,比如数字、字符串等。它将普通的数据变成响应式数据,可以监听数据的变化。使用 Ref 时,我们可以通过 .value 来访问和修改数据的值。 Reactive :

    2024年04月25日
    浏览(50)
  • 前端Vue篇之v-model 是如何实现的,语法糖实际是什么?v-model 可以被用在自定义组件上吗?如果可以,如何使用?

    v-model 在 Vue.js 中扮演着重要的角色,实现了表单输入和应用状态之间的双向数据绑定。其具体实现方式取决于所绑定元素的类型。 作用在表单元素上 : 当 v-model 用于表单元素(如 input、textarea)时,它动态绑定了 input 的 value 到指定的变量,并在触发 input 事件时动态更新这

    2024年04月28日
    浏览(42)
  • vue面试知识点

    Unsplash class 和 style 使用动态属性,使用驼峰式写法 v-if 和 v-show v-if 不渲染不满足判断条件的模块, v-show 渲染但不显示,使用场景:是否多次切换或频繁更新条件状态 keep-alive 缓存组件,使用场景:频繁切换,不需要重复渲染 v-for 中添加唯一的 key 为了高效的更新虚拟 DOM,

    2024年02月11日
    浏览(44)
  • vue知识点

    vue是什么 用于构建用户界面的渐进式开源JS框架,是创建单页应用的Web框架 核心特征: 数据驱动mvvm 组件化 指令系统 SPA与MPA SPA 单页应用: 动态重写当前页面数据用以用户交互 MPA: 多页应用,每一个页面都是主页面 SPA首加载慢: 原因:网络延时,资源体积太大 解决办法

    2024年02月11日
    浏览(38)
  • Vue知识系列(7)每天10个小知识点

    👍 点赞,你的认可是我创作的动力! ⭐️ 收藏,你的青睐是我努力的方向! ✏️ 评论,你的意见是我进步的财富! Vue 的过滤器(Filters)是一种用来处理文本格式化的功能。它们允许你在插值表达式 {{ }} 中使用管道符 | ,将数据经过一系列的处理后再显示在视图中。以下

    2024年02月07日
    浏览(65)
  • Vue知识系列(1)每天10个小知识点

    👍 点赞,你的认可是我创作的动力! ⭐️ 收藏,你的青睐是我努力的方向! ✏️ 评论,你的意见是我进步的财富! Vue.js 中的修饰符是一种用于改变指令行为的特殊标记,它们可以用于指令的事件监听和双向数据绑定。修饰符以点号的形式添加到指令之后。以下是有关V

    2024年02月09日
    浏览(47)
  • Vue知识点汇总【持更】

    目录 1 vue的两个特性 1.1 数据驱动视图 1.2 双向数据绑定  2 MVVM工作原理 3 vue 的指令 3.1 内容渲染指令 3.2 属性绑定指令 3.3 事件绑定指令 3.4 事件修饰符  3.5 按钮修饰符 3.6 双向数据绑定指令 3.7 条件渲染指令 3.8 列表渲染指令  4 vue 的生命周期和生命周期函数  4.1 生命

    2024年02月15日
    浏览(40)
  • Vue入门——核心知识点

    Vue是一套用于 构建用户界面 的 渐进式 JS框架。 构建用户界面:就是将后端返回来的数据以不同的形式(例如:列表、按钮等)显示在界面上。 渐进式:就是可以按需加载各种库。简单的应用只需要一个核心库即可,复杂的应用可以按照需求引入各种Vue插件。 采用组件化模式

    2024年02月06日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包