vue2框架简易版响应式设计(观察者模式)

对于vue.js中的属性值我们要格外关注:

$attrs 获取当前传递的参数

$listeners 获取当前组件的自定义事件

$children 获取当前组件所有子组件

$parent 获取当前组件所有父组件

$options 获取当前vue实例参数信息

$refs 获取ref所有的引用节点

设计原则:单一职责,一个类或一个函数,只做一件事。

数据定义后页面更新

页面数据切换操作data数据

添加数据劫持方法

// Vue.js 
//Observer专门用于数据劫持
class Observer {data;constructor(data) {this.data = datathis.walk()}defineProperty(data, key, value) {Object.defineProperty(data, key, {get() {console.log(`使用了${key}这个属性`);return value},set(val) {console.log(`修改了${key}属性`, val);value = val}})}walk() {Object.keys(this.data).forEach(el => {this.defineProperty(user, el, this.data[el])})}
}const user = {username:'xiaowang',age:11
}new Observer(user)
console.log(user.username);

对于data来说,我们自己数据劫持存了一份在$data,并且还将$data中每个数据都再次存在了vue实例上,创建Vue类。

class Vue {constructor(options) {this.$options = optionsthis.$data = options.data()this.$el = options.el//$data上的所有数据都要数据劫持new Observer(this.$data)//$data存放所有的数据//会将$data的数据挂并挂载到this身上this.proxy()}proxy() {Object.keys(this.$data).forEach(key => {Object.defineProperty(this, key, {get() {return this.$data[key]},set(val) {this.$data[key] = val}})})}
}

进行模版渲染,这里仅仅渲染一层,如果多层可以执行递归。

//模版渲染
class Compile{constructor(el,data){this.$el = document.querySelector(el)this.$data = datathis.compiler()}compiler(){[...this.$el.children].forEach(item=>{if(/\{\{([a-zA-z0-9]+)\}\}/.test(item.innerHTML)){const key =RegExp.$1.trim()item.innerHTML=this.$data[key]}})}
}

观察者模式

观察者模式是一种设计模式,就是一种代码规范。有两个非常重要的元素:发布者和订阅者。一个发布者可能对应多个订阅者。

对应到我们的代码,使用{{}}的标签,意味着是我们需要标记的标签,作为订阅者,在项目中提供一个发布者,一旦数据发生变化,发布者通知订阅者更新页面。

//订阅者
class Watcher {constructor(callback) {Dep.target = thisthis.callback = callbackthis.update()Dep.target = null}update() {//这一步并不是直接修改,而是更新虚拟dom,这里只是简化了this.callback()}
}//发布者
class Dep {constructor() {this.subs = []}notify() {this.subs.forEach(item => {item.update()})}
}

于此同时,在set get中需要收集wacher以及通知watcher更新数据,那么也要修改

Object.defineProperty(data, key, {get() {if (Dep.target) { //只收集编译时的watcher//依赖收集,使用这个属性就生成一个watcherdep.subs.push(Dep.target)}return value},set(val) {//一旦数据更新,Dep通知watcher更新value = valdep.notify()}})

此刻,我们简易的响应式就算完成了。

附完整代码:

//vue.js
// Observer专门用于数据劫持
class Observer {data;constructor(data) {this.data = datathis.walk()}defineProperty(data, key, value) {const dep = new Dep()Object.defineProperty(data, key, {get() {if (Dep.target) { //只收集编译时的watcher//依赖收集,使用这个属性就生成一个watcherdep.subs.push(Dep.target)}return value},set(val) {//一旦数据更新,Dep通知watcher更新value = valdep.notify()}})}walk() {Object.keys(this.data).forEach(el => {this.defineProperty(this.data, el, this.data[el])})}
}class Vue {constructor(options) {this.$options = optionsthis.$data = options.data()this.$el = options.el//$data上的所有数据都要数据劫持new Observer(this.$data)//$data存放所有的数据//会将$data的数据挂并挂载到this身上this.proxy()new Compile(this.$el, this.$data)}proxy() {Object.keys(this.$data).forEach(key => {Object.defineProperty(this, key, {get() {return this.$data[key]},set(val) {this.$data[key] = val}})})}
}//模版渲染
class Compile {constructor(el, data) {this.$el = document.querySelector(el)this.$data = datathis.compiler()}compiler() {[...this.$el.children].forEach(item => {if (/\{\{([a-zA-z0-9]+)\}\}/.test(item.innerHTML)) {const key = RegExp.$1.trim()//实际上vue底层不是直接innerHTML// item.innerHTML=this.$data[key]const render = () => item.innerHTML = this.$data[key]new Watcher(render)}})}
}
//订阅者
class Watcher {constructor(callback) {Dep.target = thisthis.callback = callbackthis.update()Dep.target = null}update() {//这一步并不是直接修改,而是更新虚拟dom,这里只是简化了this.callback()}
}//发布者
class Dep {constructor() {this.subs = []}notify() {this.subs.forEach(item => {item.update()})}
}
<!DOCTYPE html>
<html lang="en">//HTML
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div id="app"><p>{{username}}</p><p>{{age}}</p></div>
</body>
<script src="./vue.js"></script>
<script>const app = new Vue({el: '#app',data() {return {username: 'xiaoming',age: 10}}})console.log(app);</script></html>

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

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

相关文章

day4 节点两两交换

ListNode* swapPairs(ListNode* head) { ListNode* dummyHead new ListNode(0); // 设置一个虚拟头结点 dummyHead->next head; // 将虚拟头结点指向head&#xff0c;这样方便后面做删除操作 ListNode* cur dummyHead; while(cur->next ! nullptr && cur->…

编译原理头歌实验:实验4《算符优先分析法设计与实现》(C语言版)

任务描述 本关任务&#xff1a;加深对语法分析器工作过程的理解&#xff1b;加强对算符优先分析法实现语法分析程序的掌握&#xff1b;能够采用一种编程语言实现简单的语法分析程序&#xff1b;能够使用自己编写的分析程序对简单的程序段进行语法翻译。 相关知识 为了完成本…

【大连民族大学C语言CG题库练习题】——猪的安家问题

【问题描述】 Andy和Mary养了很多猪。他们想要给猪安家。但是Andy没有足够的猪圈&#xff0c;很多猪只能够在一个猪圈安家。举个例子&#xff0c;假如有16头猪&#xff0c;Andy建了3个猪圈&#xff0c;为了保证公平&#xff0c;剩下1头猪就没有地方安家了。Mary生气了&#xf…

(一)WtBtRunner回测大体流程

WtBtRunner是回测的主程序&#xff0c;启动改程序时&#xff0c;会进行配置文件和dll的加载 解析参数&#xff0c;由cppcli::Option完成参数解析初始化日志打印 std::string filename;if (lParam->exists())filename lParam->get<std::string>();elsefilename …

Java集合(已重写-废弃了)

# 精辟总结 其实各种八股文资料&#xff0c;他也就是围绕着核心知识展开提问的&#xff0c;你只要根据八股文把核心知识提炼出来&#xff0c;形成核心知识体系&#xff01; Java集合那是重点中的重点。最基本的概念要懂&#xff0c;核心的概念&#xff0c;那要滚瓜烂熟。 Ja…

【recrutment / Hiring / Job / Application】

Interviewee I), objected/targeted job/position1.1) Azure 平台运维工程师&#xff08;comms&social&#xff09;1.1.1), comms communication and social, for talk, content1.1.2) Cloud computing1.1.3) 拥有ITI/MCSE/RHCE相关认证或Azure认证(如Az204/Az304 have/own…

【计算机视觉】基于OpenCV计算机视觉的摄像头测距技术设计与实现

基于计算机视觉的摄像头测距技术 文章目录 基于计算机视觉的摄像头测距技术导读引入技术实现原理技术实现细节Python-opencv实现方案获取目标轮廓步骤 1&#xff1a;图像处理步骤 2&#xff1a;找到轮廓步骤完整代码 计算图像距离前置技术背景与原理步骤 1&#xff1a;定义距离…

[传智杯 #3 决赛] 面试

题目背景 disangan233 和 disangan333 去面试了&#xff0c;面试官给了一个问题&#xff0c;热心的你能帮帮他们吗&#xff1f; 题目描述 现在有 n 个服务器&#xff0c;服务器 i 最多能处理 ai​ 大小的数据。 接下来会有 k 条指令 bk​&#xff0c;指令 i 表示发送 bi​ …

海德汉(HEIDENHAIN)CNC数据采集(可免授权)

一&#xff0c;概述 海德汉 常见的系统一般有530、640系统&#xff0c;采集一般有两种方法&#xff1a; &#xff08;1&#xff09;购买海德汉官方的SDK&#xff0c;HeidenhainDNC COM Component&#xff0c;安装之后有相应的demo&#xff0c;支持的语言有C#、C/C。此方法还需…

面试篇之微服务(二)

目录 服务容灾 21.什么是服务雪崩&#xff1f; 22.什么是服务熔断&#xff1f;什么是服务降级&#xff1f; 什么是服务熔断&#xff1f; 什么是服务降级&#xff1f; 有哪些熔断降级方案实现&#xff1f; 23.Hystrix怎么实现服务容错&#xff1f; 24.Sentinel怎么实现限…

JSP格式化标签 parseDate将指定时间格式字符串转为真正的date对象

格式化标签最后一个就是 parseDate 作用 将一个日期/时间格式字符串 转为 真正的date时间类型 有点无语 这种 东西应该都是在java中去做的 而不是在java中 这个建议也是做个了解即可 作用不是那么大 基本语法如下 这里 我们 直接编写代码如下 <% page contentType"…

【限时免费】20天拿下华为OD笔试之【哈希集合】2023B-明明的随机数【欧弟算法】全网注释最详细分类最全的华为OD真题题解

文章目录 题目描述与示例题目描述输入描述输出描述&#xff1a;示例 1输入输出说明 解题思路代码PythonJavaC时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 题目描述与示例 题目描述 明明生成了N 个 1 至 500 之间的随机整数。请你删去其中重复的数字&#xff0c;即…

JSP格式化标签 parseNumber指定格式字符串转数字类型

好 我们继续来说格式化标签 parseNumber 它的作用是讲一个字符串 转换为指定格式的数值型 老实说 这东西 作为了解把 实际开发中都不是用得少 我建议还是在java端就处理好 不建议在jsp中高这种类型转换的操作 基本格式如下 这几个属性都是我们这几期jsp标签的老朋友了 我们…

【STM32】STM32学习笔记-新建工程(04)

00. 目录 文章目录 00. 目录01. 创建STM32工程02. STM32工程编译和下载03. LED测试04. 型号分类及缩写05. 工程结构06. 附录 01. 创建STM32工程 【STM32】STM32F103C8T6 创建工程模版详解(固件库) 02. STM32工程编译和下载 2.1 选择下载器位ST-Link Debugger 2.2 勾选上电…

基于Spring、SpringMVC、MyBatis的企业博客网站

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于Spring、SpringMVC、MyBatis的企业博…

python 3.11 运行 timm 0.6.12无法import

python3.11 安装了 timm 0.6.12 后&#xff0c;在import timm时报错&#xff1a; ValueError: mutable default <class timm.models.maxxvit.MaxxVitConvCfg> for field conv_cfg is not allowed: use default_factory 在hugging face官方的issue中给出了解决方案&…

认识成交量VOL,搞懂量价关系

一、认识成交量VOL 1、成交量VOL的含义 VOL是一个成交量指标&#xff0c;是指个股或者大盘一定时间内的成交数量&#xff0c;一般的炒股软件中都是指成交总手数&#xff08;1手100股&#xff09;。 成交量体现在炒股软件上就是一根竖着的柱子&#xff0c;成交量越大&#xff0c…

Redis常见类型

常用类型String字符串类型Hash字典类型List列表类型Set集合类型ZSet有序集合类型 Java程序操作Redis代码操作Redis 常用类型 String字符串类型 使用方式&#xff1a; 使用场景&#xff1a; Hash字典类型 字典类型(Hash) 又被成为散列类型或者是哈希表类型&#xff0c;它…

基于Hexo框架搭建个人博客(Node.js、npm、Hexo框架以及Gitee新手教程)

下面是使用Node.js、npm、Hexo框架以及Gitee来生成博客系统的详细步骤&#xff1a; 确保你的计算机已经安装了Node.js。你可以在命令行输入以下命令来检查Node.js是否已经安装&#xff1a; node -v安装npm&#xff08;Node.js的包管理器&#xff09;。npm通常随Node.js一起安装…

数据库-MySQL之数据库必知必会22-26章

第 22 章 使用视图 视图是虚拟的表。与包含数据的表不一样&#xff0c;视图只包含使用时动态检索数据的查询。 使用视图 视图用CREATE VIEW语句来创建。 使用SHOW CREATE VIEW viewname&#xff1b;来查看创建视图的语句。 用DROP删除视图&#xff0c;其语法为DROP VIEW view…