vue设计原理-带你重走vue诞生路程

我们首先看下面这个小demo
在这里插入图片描述

demo源码:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>重走vue</title><style>div {width: 300px;padding: 15px;background-color: aqua;color: #000;margin: 50px auto;border: #13c159 double;border-radius: 20px;}div>p {padding: 5px;font-weight: 800;}</style>
</head><body><div><p id="name"></p><p id="age"></p><p id="appearance"></p></div><script>let student = {name: '林江涛',age: '刚满18岁(没多少年)',appearance: '江西吴彦祖'}// 显示姓名function showName() {document.querySelector('#name').textContent = `姓名: ${student.name}`}//显示年龄function showAge() {document.querySelector('#age').textContent = `年龄: ${student.age}`}//显示外貌function showAppearance() {document.querySelector('#appearance').textContent = `外貌: ${student.appearance}`}showName()showAge()showAppearance()</script>
</body></html>

从上面源码可以看出,这个demo设计为,展示一个对象student的数据,
在实际开发中,我们往往会需要改变student这个对象中的一些属性,然后在页面上展示
如下
在这里插入图片描述
我们可以看见,改变了student对象的name属性后,页面并没有跟着变化,
在没有vue的世界里自然是这样,

我们要想改动了student对象的name属性,就得再去调用对应的渲染函数
在这里插入图片描述

那为什么是调用showName()呢?为什么不是调用showAge()或showAppearance()?

你们看到这可能就得说,你这问的什么智障问题? showName()这个函数不就是用来展示student.name的值吗,

student.name的值改变了,要想页面跟着变,当然得重新调用 showName()

好的,如果你已经十分明白的知道了这个,那我们把上面的逻辑用人话整理一下

为什么student.name值改变了,要想使页面对应变化,需要调用showName()而不是其它函数?

是因为showName就是用来展示student.name这个属性的值得,showName在运行的过程中用到了student.name这个属性

换句更加简洁的话来说就是,showName()依赖于student.name这个属性,

showAge(),showAppearance()或其它函数,没有没有用到student.name这个属性,也就是说没有依赖于这个属性,所以从逻辑上来讲应该调用showName()这个函数,而不是其他函数

同理.,如果将来student.appearance这个属性变了,就应该去调用showAppearance()这个函数.因为showAppearance()依赖于student.appearance,
这样页面才会对应变化
在这里插入图片描述
那现在看起来一切和谐,没有什么问题,数据的改动,页面也能对应的改动

看起来没有问题,其实隐藏着一个巨大的问题,因为这个demo仅仅只有三个属性,依赖于它的函数也仅仅有三个,
但在实际的项目中,往往是拥有成千上万个对象,对象又可能有成千上万个属性,而依赖于此的对象更是数不胜数

在这种情况下,上面的写法,就完全不适用了你会发现,你改了一个属性,你完全不知道你应该去调用那些函数,或者这些函数根本就没写在同一个文档中,更甚者,你甚至不知道这个属性会在哪里被更改,比如直接控制台更改

这简直是灾难,

那能不能有一种方法,当我改动了一个属性后,会自动去调用依赖于它的方法?

这样的话,那既能避免手动调用有遗漏和不知道应该调用那个函数,又能保证页面和数据是统一的

那有目标了,就得想办法实现它

一个对象的属性,被改变了,我们能知道它被改变了,这时候就可以请出我们的defineProperty了
在这里插入图片描述
使用Object.defineProperty()修改一下student.name属性,这样每当student.name属性被获取时会调用对应的get函数
设置时会调用set函数
在这里插入图片描述

我们再对这两个函数进行一个小小的修改,加个变量存储student.name的值,这样赋值取值的时候就能有数据,
再分别给函数加个console.log()这样我们就能知道函数到底是否运行了

如下,打开控制台可以看到,函数是正常运行了
在这里插入图片描述

我们在对student.name进行修改,可以看到,现在程序自己知道我们读取了student.name的值或给它赋值了

在这里插入图片描述

知道了这个之后,那想让页面跟着变,自然就是调用对应的函数
如下
在这里插入图片描述

然后我们再修改student.name的值就能发现,页面也会跟着变化了

在这里插入图片描述
恭喜,如果你看到这,那我们已经完成阶段性胜利了,因为我们以及初步完成了数据的响应式,
即,当数据的值发生更改->对应页面也发生更改,

但是这样还不够,因为这代码写死了,意味着上面的数据变化,页面也对应变化的功能,仅仅只能针对student.name这一个属性,

	let internalVal = student.userObject.defineProperty(student, 'name', {get: () => {console.log('student.name被读取了')return internalVal},set: val => {internalVal = valconsole.log('student.name被赋值了赋值为' + val)showName()}})

那这是肯定不行的,因为我们的目的,是为了让所有的数据变化时,依赖于它的函数都能执行也就是页面都能做出响应的改变

所以我们就得想个办法,该如何让所有的数据改变时,依赖于他的方法都能执行?

既然Object.defineProperty这个方法是给某一个属性修改了,那么我们是不是就可以封装一个方法,然后在里面写一个循环,循环遍历传进来的对象给他每一个属性都修改成上面那种样子,不就能监控对象的所有属性了吗

示例如下

声明一个函数,这个函数接收一个对象,然后把对象遍历一遍,再使用defineProperty让对象的每一个属性都修改为拥有get和set方法的属性

	function observe(o) {for (let k in o) {let internalVal = o[k]Object.defineProperty(o, k, {get: () => {console.log(`对象的.${k}被读取了`)return internalVal},set: val => {internalVal = valconsole.log(`对象的.${k}被赋值了赋值为` + val)}})}}observe(student)

效果如下,
如图,可以看到修改或赋值student的所有属性

在这里插入图片描述

修改完之后,问题就来了,我该如何在set里面绑定调用依赖于对应属性的函数呢?

因为我们在set方法里压根就不清楚会调用那些函数,

这个时候我们就得回过头想一想,为什么要调用这些函数?因为这些函数依赖于student1,对象的属性
那也就是说,student[key]的操作,也就是说,会调用get这个方法,

那就代表着,可以让get收集访问过这个属性的函数名称,然后在set里面就可以使用循环依次调用了

但是这样还不够,这样只能知道到底get被调用了,不知道到底是谁调用了,

那怎么办?在家一层代理,这样询问代理就能知道具体是那个函数访问了属性

代码如下

	let distribute;let internalVal = student.userfunction observe(o) {for (let k in o) {let internalVal = o[k]let fnArr = []Object.defineProperty(o, k, {get: () => {if (distribute) {fnArr.push(distribute)}console.log(`对象的.${k}被读取了`)return internalVal},set: val => {internalVal = valconsole.log(`对象的.${k}被赋值了赋值为` + val)for (let i = 0; i < fnArr.length; i++) {fnArr[i]()}}})}}observe(student)function distributeFun(fn) {distribute = fn;fn()distribute = null}distributeFun(showName)distributeFun(showAge)distributeFun(showAppearance)student.name = '吴彦祖'student.age = 100

效果如下,

在这里插入图片描述

嗯,还有一些小bug比如再次调用age依赖的函数依然会加进去,

这里做一个去重就好
在这里插入图片描述

呐,大功告成

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

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

相关文章

JAVA如何利用接口实现多继承问题

hello&#xff0c;上文带大家学习了java中类的继承&#xff0c;我们可以创建一个父类&#xff0c;将类中的共性抽取出来&#xff0c;通过子类继承的方式来实现代码的复用。今天带大家学习不同类之间的另外几种关系&#xff0c;即多态抽象类和接口。 多态的概念 多态&#xff0c…

Vue 3的Composition API和vue2的不同之处

Vue 3的Composition API是Vue.js框架的一个重要更新&#xff0c;它提供了一种新的组件逻辑组织和复用方式。在Vue 2中&#xff0c;我们通常使用Options API&#xff08;data、methods、computed等&#xff09;来组织组件的逻辑&#xff0c;但这种组织方式在处理复杂组件时可能会…

实体店好做还是电商平台好做?哪个发展前景较高?

我是电商珠珠 大部分人面对新的一年都会比较迷茫&#xff0c;想要创业会自己增加收入&#xff0c;却在开店和线上做电商这两者之间犹豫不决。不知道哪个更加合适自己&#xff0c;换句话来说&#xff0c;就是不知道哪个赔付率低一点。 现在这个行情&#xff0c;按照网友的说法…

C++ string类详解及模拟实现

目录 【本节目标】 1. 为什么学习string类&#xff1f; 1.1 C语言中的字符串 1.2 面试题(暂不做讲解) 2. 标准库中的string类 2.1 string类(了解) 2.2 string类的常用接口说明&#xff08;注意下面我只讲解最常用的接口&#xff09; 3. string类的模拟实现 3.1string类常用…

Express学习(一)

Express Express简介 什么是Express 官方给出的概念&#xff1a;Express是基于Node.js平台&#xff0c;快速、开放、极简的web开发框架。 通俗的理解&#xff1a;Express的作用和Node.js内置的http模块类似&#xff0c;是专门用来创建Web服务器的。进一步理解Express 不使用E…

【软件使用】Markdown编辑器第一次使用介绍

【软件使用】Markdown编辑器第一次使用介绍 markdown格式支持的软件有&#xff1a;VS Code 和 Typora&#xff0c;CSDN写网页博文也是用的.md&#xff0c;CSDN能支持导入的文件也是以.md格式结尾的文件名。 欢迎使用Markdown编辑器 你好&#xff01; 这是你第一次使用 Markd…

C语言——结构体(位段)、联合体、枚举

hello&#xff0c;大家好&#xff01;我是柚子&#xff0c;今天给大家分享的内容是C语言中的自定义类型结构体、联合体以及枚举&#xff0c;有什么疑问或建议可以在评论区留言&#xff0c;会顺评论区回访哦~ 一、结构体 struct a.结构体声明 不同于数组的是&#xff0c;结构…

【CSP试题回顾】202212-2-训练计划

CSP-202212-2-训练计划 解题思路 输入和初始化&#xff1a; 首先&#xff0c;代码从输入中获取项目的截止日期和项目数量。然后&#xff0c;它初始化一个项目列表&#xff0c;每个项目都有其依赖项、被依赖的项目集合、完成时间、总完成时间&#xff08;包括依赖链&#xff09…

【JavaSE】面向对象——多态性

多态性 多态性的概念 所谓多态性&#xff0c;理解为一个事物的多种形态。具体点就是去完成某个动作时&#xff0c;不同的对象会产生不同的状态。 多态性的好处 多态在Java中指的是父类的引用指向子类的对象&#xff0c;或者可以说是子类的对象赋给父类的引用。这样在我们的…

SpringBoot实现分页模糊查询

1. Navicat查询数据 Navicat中查询所有数据 SELECT * FROM sys_user;Navicat中查询前两条数据&#xff08;俩种方式&#xff09; SELECT * FROM sys_user LIMIT 2; //从0开始&#xff0c;第一个参数是起始位置即(pageNum-1)*pageSize&#xff0c;第二个参数是步长 SELECT * …

项目部署后 通过公网IP访问不到的问题解决

目录 1.检查项目是否在运行(第二行命令) 2.检查所用服务器防火墙是否打开 3.检查linux系统防火墙有没有打开 问题如图: 首先确保项目已经成功部署 1.检查项目是否在运行(第二行命令) 第一行命令是监听58080端口,我的项目是使用该端口 2.检查所用云服务器防火墙是否打开 我…

分享77个Html杂七杂八模板,总有一款适合您

分享77个Html杂七杂八模板&#xff0c;总有一款适合您 77个Html杂七杂八模板下载链接&#xff1a;https://pan.baidu.com/s/1-RyIKaxdCu3dbnlMFMwviw?pwd8888 提取码&#xff1a;8888 学习知识费力气&#xff0c;收集整理更不易。知识付费甚欢喜&#xff0c;为咱码农谋福…

每日好题3.5

前缀和 这个题目巨妙&#xff0c;打的时候没写出来&#xff0c;后面补题发现太牛了 思路&#xff1a;当前区间左端点 L L L &#xff0c;当我们向右移动一次&#xff0c;就相当于&#xff0c;原式 - f ( L ) f ( L 1 e 18 ) f(L) f(L 1e18) f(L)f(L1e18)&#xff0c;值就…

linuxOPS基础_服务器构成

服务器的重要结构组成 家用电脑组成&#xff1a; CPU、主板、内存条、显卡、硬盘、电源、风扇、网卡、显示器、机箱、键盘鼠标等等。 CPU CPU是电脑的大脑&#xff0c; CPU发展史&#xff1a; 32 位CPU&#xff1a;最大的内存寻址地址2^32&#xff0c;大约4G的大小。 CP…

CSS3新特性

简介 继CSS2之后&#xff0c;CSS3增加了很多新的特性&#xff0c;虽然W3C仍在规范中&#xff0c;但是很多新的CSS3属性已经在很多现代浏览器中得到了支持。 CSS3边框 在CSS3中&#xff0c;可以创建圆角边框&#xff0c;添加边框阴影&#xff0c;设置边框图片&#xff0c;利用…

计算机组成原理之机器:计算机系统的基本概念

计算机组成原理之机器 笔记来源&#xff1a;哈尔滨工业大学计算机组成原理&#xff08;哈工大刘宏伟&#xff09; Chapter1&#xff1a;计算机系统的基本概念 1.1 计算机系统简介 从物理构成的角度对计算机系统分层 计算机组成原理主要关注微体系结构&#xff08;Mirco-arc…

【无标题】计算机主要应用于哪些领域

科学计算&#xff08;或称为数值计算&#xff09;、数据处理&#xff08;信息管理&#xff09;、辅助工程、生产自动化、人工智能。1、科学计算&#xff08;或称为数值计算&#xff09;&#xff1a;早期的计算机主要用于科学计算。目前&#xff0c;科学计算仍然是计算机应用的一…

【原理图PCB专题】Allegro模块化移动器件报...has the LOCKED property怎么解锁?

在模块化原理图时,PCB也需要做一个模块.mdd文件。这时需要先画好图纸然后再制作模块化文件。 修改文件时会发现模块化器件报错,无法编辑模块内部器件和走线,器件和走线都被LOCKED,如下所示报错内容: Symbol "U1" Selected Cannot edit Symbol "U1". M…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:组件标识)

id为组件的唯一标识&#xff0c;在整个应用内唯一。本模块提供组件标识相关接口&#xff0c;可以获取指定id组件的属性&#xff0c;也提供向指定id组件发送事件的功能。 说明&#xff1a; 从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容…

代码随想录算法训练营第九天

28. 实现 strStr() &#xff08;本题可以跳过&#xff09; 方法&#xff1a; 方法一&#xff1a; 暴力法 i 表示最多能移动到n-m位置&#xff0c; 超过则退出循环。j表示haystack 初始位置k表示needle的初始位置如果haystack [j] needle[k]且 k<m 则 j, k; 如果 km 则返…