二、什么是Vue中的响应式?Vue的响应式原理

什么是Vue中的响应式

Vue中的响应式,简而言之就是当数据发生变化时,页面跟随变化。使用过Vue的v-model都有比较深刻的感受,我们在代码中修改双向绑定的数据后,页面上的数据也会自动更新,页面跟随变化
我们看个例子:

<div id="app"><div>价格:¥{{ price }}</div><div>支付金额:¥{{ price * quantity }}</div><button @click="changePrice">改变价格</button>
</div>
var app = new Vue({el: '#app',data() {return {price: 5.0,quantity: 2};},methods: {changePrice() {this.price = 10;}}
})

在这个例子中,我们调用changePrice方法,修改price的值,页面上价格 、支付金额,都会自动改变。这就是Vue中的响应式

Vue中如何实现响应式

当数据发生变化后,会重新对页面渲染,这就是Vue响应式,那么这一切是怎么做到的呢?

想完成这个过程,我们需要完成这几个步骤:

(1)侦测数据的变化(数据劫持 / 数据代理)
(2)收集视图依赖了哪些数据(依赖收集)
(3)数据变化时,自动“通知”需要更新的视图部分,并进行更新(发布订阅模式)

1.侦测数据的变化(数据劫持 / 数据代理)

在Javascript中,如何侦测一个对象的变化?我们有两种办法可以侦测到变化:使用Object.defineProperty和ES6的Proxy,这就是进行数据劫持或数据代理。

在Vue2中,使用的是Object.defineProperty的方式侦测数据的变化,
类似如下代码,当属性被读取或设置时,相应的getter或setter将被调用。修改obj.value的值时,会监听到obj.value,执行set方法,执行console.log(obj.value)时,又会调用get方法。

    <script>const obj = {};// 定义属性'value',包含getter和setterObject.defineProperty(obj, "value", {get() {console.log("get value");return this._value;},set(newValue) {console.log("set value");this._value = newValue;},// 可以通过这个属性来控制属性的可枚举性configurable: true,// 可以通过这个属性来控制属性的可写性enumerable: true,});obj.value = 5;console.log(obj.value); // get value ,set value, 5</script>

但在Vue3中,使用的是ES6的Proxy的方式侦测数据的变化。
Proxy对象允许你拦截并自定义对象的基本操作,包括属性访问和修改。这使得你可以创建一个代理对象,当访问或修改目标对象的属性时,会触发预定义的行为。如下代码示例:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>基础 ref()</title></head><body><button id="updateButton">点击+1</button><div id="message"></div><script>const createRef = (initialValue) => {return new Proxy({ value: initialValue },{get(target, key) {return target[key];},set(target, key, value) {target[key] = value;if (key === "value") {updateDisplay(); // 当.value被设置时,更新DOM}return true;},});};// 初始化refconst numberRef = createRef(0);// 更新DOM的函数const updateDisplay = () => {document.getElementById("message").innerText = numberRef.value;};// 绑定按钮点击事件document.getElementById("updateButton").addEventListener("click", () => {numberRef.value++; // 点击按钮时计数器加一});// 初始显示updateDisplay();</script></body>
</html>

2.收集视图依赖了哪些数据(依赖收集)

当模板渲染或计算属性计算时,Vue 会追踪哪些数据被访问了。这通过 Dep 类和 Watcher 类完成。Watcher 会在读取数据时将自身添加到数据的依赖列表中。

订阅者 Dep
收集依赖需要为依赖找一个存储依赖的地方,为此我们创建了Dep,它用来收集依赖、删除依赖和向依赖发送消息等。
于是我们先来实现一个订阅者 Dep 类,用于解耦属性的依赖收集和派发更新操作,说得具体点,它的主要作用是用来存放 Watcher 观察者对象。我们可以把Watcher理解成一个中介的角色,数据发生变化时通知它,然后它再通知其他地方。
Dep的简单实现

class Dep {constructor () {/* 用来存放Watcher对象的数组 */this.subs = [];}/* 在subs中添加一个Watcher对象 */addSub (sub) {this.subs.push(sub);}/* 通知所有Watcher对象更新视图 */notify () {this.subs.forEach((sub) => {sub.update();})}
}

以上代码主要做两件事情:

用 addSub 方法可以在目前的 Dep 对象中增加一个 Watcher 的订阅操作;
用 notify 方法通知目前 Dep 对象的 subs 中的所有 Watcher 对象触发更新操作

观察者 Watcher
Vue 中定义一个 Watcher 类来表示观察订阅依赖。
watcher的简单实现:

class Watcher {constructor(obj, key, cb) {// 将 Dep.target 指向自己// 然后触发属性的 getter 添加监听// 最后将 Dep.target 置空Dep.target = thisthis.cb = cbthis.obj = objthis.key = keythis.value = obj[key]Dep.target = null}update() {// 获得新值this.value = this.obj[this.key]// 我们定义一个 cb 函数,这个函数用来模拟视图更新,调用它即代表更新视图this.cb(this.value)}
}

3.数据变化时,自动“通知”需要更新的视图部分,并进行更新(发布订阅模式)

当数据被修改时,对应的 Watcher 会收到通知,并触发视图更新

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/877642.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java ArrayList和LinkedList

ArrayList ArrayList是Java中最常用的数据结构之一&#xff0c;它是一个动态数组的实现&#xff0c;允许你在程序中存储和管理一个可变大小的对象列表&#xff0c;我们可以添加或删除元素。 ArrayList 继承了 AbstractList &#xff0c;并实现了 List 接口。 基本概念 Arra…

【Linux】ARM服务器命令行安装虚拟机

在Arm服务器上安装虚拟机操作笔记 一、基础环境准备1、环境准备2、检查KVM支持3、启动并启用libvirtd服务4、创建虚拟网络&#xff08;可选&#xff09;5、使用virt-manager创建虚拟机&#xff08;支持KVM&#xff09;6、管理虚拟机9、监控和日志 二、软虚拟化替代方案1、查看虚…

6. type *(0)的神奇之处

表达式 type * (0) 在 C/C 编程中是一个常见的技巧&#xff0c;通常用于内核编程和一些系统编程场景中。这种语法形式的主要作用是获取特定类型指针的虚拟地址 0&#xff0c;从而进行类型转换或执行其他计算。接下来我们会深入分析这个表达式的具体含义和应用。 1. 表达式的基…

GPT4o编写步进电机控制代码

我给出的要求如下&#xff1a; 基于STM32F407 HAL库&#xff0c;写一个步进电机控制程序&#xff0c;需要控制8个步进电机&#xff0c;我会给出描述步进电机的结构体变量&#xff0c;基于这些变量需要你做出以下功能&#xff0c;电机脉冲通过定时器中断翻转脉冲引脚的电平实现…

安科瑞电气防火在线保护器 ASCP210系列适用于汽车充电桩

安科瑞电气防火限流式保护器 传统保护方式采用电磁脱扣式断路器&#xff0c;检测到短路时&#xff0c;脱扣器动作&#xff0c;分断时间在毫米级&#xff0c;无法阻断短路电流。较好的方式是采用响应速度快的限流技术和器件。 电弧也有克星&#xff0c;可以微秒被扼杀在摇篮中&…

Vscode——如何实现 Ctrl+鼠标左键 跳转函数内部的方法

一、对于Python代码 安装python插件即可实现 二、对于C/C代码 安装C/C插件即可实现

【MySQL进阶之路】数据的查询

目录 建表 全列查询 指定列查询 查询表达式 指定别名 结果去重 WHERE 条件查询 模糊查询 结果排序 筛选分页结果 不同子句的执行顺序 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 建表 CREATE TABLE grades( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, name …

视觉巡线小车(STM32+OpenMV)——技术总结

在现代机器人技术中&#xff0c;视觉巡线是一种常见的导航方式&#xff0c;它允许机器人通过识别和跟踪地面上的线路来自主导航。本文将总结使用STM32微控制器和OpenMV视觉模块来实现视觉巡线小车的关键技术和步骤。 引言 视觉巡线小车是一种基于视觉识别技术的智能机器人&am…

CF 966 Div3 F. Color Rows and Columns

原题链接&#xff1a;Problem - F - Codeforces 题意&#xff1a;多测&#xff0c;每组测试数据给出n和k&#xff0c;n代表有n个长方形&#xff0c;k代表需要的到k分&#xff0c;每个长方形都有宽和高&#xff0c;每次可以填涂一个格子&#xff0c;如果填满一列或者一行就可以…

前端技巧——复杂表格在html当中的实现

应用场景 有时候我们的表格比较复杂&#xff0c;表头可能到处割裂&#xff0c;我们还需要写代码去完成这个样式&#xff0c;所以学会在原生html处理复杂的表格还是比较重要的。 下面我们来看这一张图&#xff1a; 我们可以看到有些表头项的规格不太一样&#xff0c;有1*1 2*…

雅菲奥朗 FinOps 认证培训:开启企业云财务管理转型之路

前言&#xff1a; 在当今快速变化的商业环境中&#xff0c;企业面临着前所未有的IT财务挑战。随着云计算和数字化转型的推进&#xff0c;传统的财务管理方式已经不能满足“企业上云”的需求。FinOps&#xff0c;即“云财务管理”应运而生&#xff0c;成为帮助企业实现IT财务流…

Oracle Index Partition索引分区的管理

Oracle索引分区的管理是数据库管理中的重要任务之一&#xff0c;它涉及索引的创建、维护、重建以及优化等多个方面。以下是对Oracle索引分区管理的详细解析&#xff1a; 一、索引分区的概念 索引分区&#xff08;Partitioned Index&#xff09;是针对分区表而言的&#xff0c…

虚幻引擎游戏开发 | 程序化生成道具位置 Randomize Height

当地图上有无数个收集物【如水晶】&#xff0c;一键随机化高度 应用前 应用后 这时候水晶的高度是离散型地在0和110两个数中平均概率地选择。 如果要有权重地分布高度&#xff0c;减少高位水晶的比例&#xff08;由于过多连续跳跃会让玩家无聊和难以持续专注&#xff09;可以加…

R语言统计分析——回归中的异常观测值

参考资料&#xff1a;R语言实战【第2版】 一个全面的回归分析要覆盖对异常值的分析&#xff0c;包括离群点、高杠杆点和强影响点。这些数据点需要更深入的研究&#xff0c;因为它们在一定程度上与其他观点不同&#xff0c;可能对结果产生较大的负面影响。 1、离群点 离群点是指…

[ACL 2024] Revisiting Knowledge Distillation for Autoregressive Language Models

Contents IntroductionMethodRethinking Knowledge Distillation for Autoregressive LMsImproving Knowledge Distillation with Adaptive Teaching Modes ExperimentsReferences Introduction 作者提出 Autoregressive KD with Adaptive Teaching Modes (ATKD)&#xff0c;通…

拦截器实现 Mybatis Plus 打印含参数的 SQL 语句

1.实现拦截器 package com.sample.common.interceptor;import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import or…

java之类和对象的介绍

1.面向对象和面向过程的概念&#xff1a; 面向对象&#xff1a;面向对象是解决问题的一种思想&#xff0c;主要依靠对象之间的交互完成一件事。 面向过程&#xff1a;注重完成一件事情的过程&#xff0c;后续代码维护扩展较为麻烦。 以洗衣服为例&#xff0c;面向对象为传统…

模糊测试技术与高效模糊测试策略设计(第一篇)

一、概述 模糊测试&#xff08;Fuzzing&#xff09;是一种自动化测试技术&#xff0c;通过向目标软件输入大量随机或异常数据来发现潜在的安全漏洞。这种技术在软件安全研究中至关重要&#xff0c;尤其适用于发现未知漏洞。本文将详细讲解如何使用模糊测试工具&#xff0c;以及…

软件测试 |属性获取与断言

1.断言简介 断言时候UI自动化测试的三要素之一&#xff0c;是UI自动化测试中不可或缺的部分。我们使用定位器到定位元素后&#xff0c;通过测试脚本进行业务交互操作时&#xff0c;想要验证交互操作过程中的结果正确性就需要用到断言。 2.常规的UI自动化测试中使用的断言 在…

vue3基础ref,reactive,toRef ,toRefs 使用和理解

文章目录 一. ref基本用法在模板中使用ref 与 reactive 的区别使用场景 二. reactive基本用法在模板中使用reactive 与 ref 的区别使用场景性能优化 三. toRef基本用法示例在组件中的应用主要用途对比 ref 和 toRef 四. toRefs基本用法示例在组件中的应用主要用途对比 ref 和 t…