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.user
	Object.defineProperty(student, 'name', {
	  get: () => {
	    console.log('student.name被读取了')
	    return internalVal
	  },
	  set: val => {
	    internalVal = val
	    console.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 = val
	        console.log(`对象的.${k}被赋值了赋值为` + val)
	      }
	    })
	  }
	}
	observe(student)

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

在这里插入图片描述

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

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

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

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

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

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

代码如下

	let distribute;
	let internalVal = student.user
	function 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 = val
	        console.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依赖的函数依然会加进去,

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

呐,大功告成

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RT-DETR 应用 CARAFE:特征内容感知重新组装

特征上采样是现代卷积神经网络架构中的关键操作,例如特征金字塔。其设计对于密集预测任务,如目标检测和语义/实例分割至关重要。在本研究中,我们提出了一种称为内容感知特征重组(CARAFE)的通用、轻量级且高效的操作符,以实现这一目标。CARAFE具有以下几个优点:(1)大的…

算法通关村第七关-青铜挑战二叉树的深度优先遍历(递归)

二叉树的深度优先遍历 今天我们来说二叉树的深度优先遍历 , 这次用简单但有点难理解的方式递归来实现 , 对应LeetCode 144,145 二叉树的前序遍历 描述 : 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 题目 : LeetCode 二叉树的前序遍历 : 144. 二叉…

【FAQ】Gradle开发问题汇总

1. buildSrc依赖Spring Denpendency时报错 来自预编译脚本的插件请求不能包含版本号。请从有问题的请求中删除该版本&#xff0c;并确保包含所请求插件io.spring.dependency-management的模块是一个实现依赖项 解决方案 https://www.5axxw.com/questions/content/uqw0grhttps:/…

K8S知识点(九)

&#xff08;1&#xff09;Pod详解-结构和定义 一级属性有下面这些&#xff1a;前两个属性是字符串&#xff0c;上面有定义 kind&#xff1a;Pod version&#xff1a;v1 下面的属性是object 还可以继续查看子属性&#xff1a;二级属性 还可以继续查看三级属性&#xff1a; 通…

微软近日限制员工访问ChatGPT!

作者 | 撒鸿宇 据CNBC报道&#xff0c;在这周四的短时间内&#xff0c;微软的员工被禁止使用ChatGPT。 微软在其内部网站的更新中表示&#xff1a;“由于安全和数据问题&#xff0c;一些AI工具不再对员工开放。”据CNBC查证&#xff0c;他们看到了一张截图&#xff0c;该截图显…

KubeSphere 社区双周报 | KubeSphere 3.4.1 发布 | 2023.10.27-11.09

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者&#xff0c;并对近期重要的 PR 进行解析&#xff0c;同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为&#xff1a;2023.10.27-2023.…

Nuxt.js——基于 Vue 的服务端渲染应用框架

文章目录 前言一、知识普及什么是服务端渲染什么是客户端渲染&#xff1f;服务端渲染与客户端渲染那个更优秀&#xff1f; 二、Nuxt.js的特点Nuxt.js的适用情况&#xff1f; 三、Vue是如何实现服务端渲染的&#xff1f;安装依赖使用vue安装 Nuxt使用npm install安装依赖包使用n…

UE特效案例 —— 角色刀光

目录 一&#xff0c;环境配置 二&#xff0c;场景及相机设置 三&#xff0c;效果制作 刀光制作 地裂制作 击打地面炸开制作 一&#xff0c;环境配置 创建默认地形Landscape&#xff0c;如给地形上材质需确定比例&#xff1b;添加环境主光源DirectionalLight&#xff0c;设…

3.如何实现 API 全局异常处理?-web组件篇

文章目录 1. 统一异常处理 1. 统一异常处理 在 Spring MVC 中&#xff0c;通过 ControllerAdvice ExceptionHandler 注解&#xff0c;声明将指定类型的异常&#xff0c;转换成对应的 CommonResult 响应。实现的代码&#xff0c;可见 GlobalExceptionHandler类。

【python】sys-path和模块搜索路径

我们在导入一个模块的时候&#xff0c;比如说&#xff1a; import math它必然是有搜索路径的&#xff0c;那到底是在哪个目录下面找呢&#xff1f;Python解释器去哪里找这个文件呢&#xff1f;只有找到这个文件才能读取、装载运行该模块文件。 它一般按照如下路径寻找模块文件…

Hutool Excel导出 配置宽度自适应 工具类

简介&#xff1a;Hutool是一款十分好用的开发工具集&#xff0c;里面包含了大部分日常开发常用的工具&#xff0c;使用简单方便&#xff0c;可以大大提升日常开发效率&#xff0c;十分推荐大家使用。这里简单总结一下基于Hutool的Excel使用。 一、Hutool依赖 <!-- Excel导出…

springboot苍穹外卖实战:七、店铺营业状态设置与查询+接口文档多端分组优化

店铺营业状态设置与查询 注意&#xff0c;先把测试类最上面的SpringBootTest注解注释掉&#xff0c;否则每次启动项目都会自动帮你测试一遍&#xff0c;导致项目启动变慢。 其次&#xff0c;该项目没有设置相应拦截器对付以下情况&#xff1a;用户使用过程中商家突然暂停营业&…

第一百七十一回 SearchBar组件

文章目录 1. 概念介绍2. 使用方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"Material3中的IconButton"相关的内容&#xff0c;本章回中将 介绍SearchBar组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在…

【Python大数据笔记_day07_hive中的分区表、分桶表以及一些特殊类型】

分区表 分区表的特点/好处:需要产生分区目录,查询的时候使用分区字段筛选数据,避免全表扫描从而提升查询效率 效率上注意:如果分区表在查询的时候呀没有使用分区字段去筛选数据,效率不变 分区字段名注意:分区字段名不能和原有的字段名重复,因为分区字段名要作为字段拼接到表后…

typora保护机制与注册逆向分析

、起因 一直比较喜欢Typora的简洁与美观&#xff08;尝试过用 vscode 搭配插件编辑 markdown 文件&#xff0c;体验还是要差一些的&#xff09;&#xff0c;突然发现自己windows机器上很久前安装的typora不让用了&#xff0c;提示&#xff1a; 幸好原始安装文件还在&#xf…

C++ 模板保姆级详解——template<class T>(什么是模板?模板分哪几类?模板如何应用?)

目录 一、前言 二、 什么是C模板 &#x1f4a6;泛型编程的思想 &#x1f4a6;C模板的分类 三、函数模板 &#x1f4a6;函数模板概念 &#x1f4a6;函数模板格式 &#x1f4a6;函数模板的原理 &#x1f4a6;函数模板的实例化 &#x1f34e;隐式实例化 &#x1f349;显式实…

Jupyter notebook 无法链接内核、运行代码

问题来源 今天想在 vscode 上使用 Jupyter notebook 跑 Python 代码&#xff0c;但无法使用&#xff0c;提示要升级内核。 Running cells with base requires the ipykernel package to be installed or requires an update. 其实这个问题存在好一段时间了&#xff0c;不过之前…

使用visualStudio发布可执行文件

编译成功后会在程序项目的路径下创建一个debug文件夹和一个release文件夹 文件夹中的具体文件入下所示 生成32位的可执行文件 32位的可执行文件可以在64位的计算机中执行&#xff0c;而64位的操作系统程序只能在64位的计算机中执行安装运行库的安装包根据电脑的版本选择合适的…

NLP实战命名实体识别

文章目录 一、导入相关包二、加载数据集三、数据预处理四、创建模型五、创建评估函数六、配置训练参数七、创建训练器八、模型训练九、模型预测 一、导入相关包 DataCollatorForTokenClassification 用于 Token 级别的分类任务 import evaluate from datasets import load_da…

tensorboard报错解决:No dashboards are active for the current data set

版本&#xff1a;tensorboard 2.10.0 问题&#xff1a;文件夹下明明有events文件&#xff0c;但用tensorboard命令却无法显示。 例如&#xff1a; 原因&#xff1a;有可能是文件路径太长了&#xff0c;导致系统无法读取文件。在win系统中规定&#xff0c;目录的绝对路径不得超…