手撕Vue-数据驱动界面改变中
经过上一篇的介绍,已经实现了观察者模式的基本内容,接下来要完成的就是将上一篇的发布订阅模式运用到 Nue 中,实现数据驱动界面改变。
在监听数据变化的章节当中,根据指定的区域和数据去编译渲染界面 这个步骤处,我写了一个注释,这个注释是这样的:第一步:给外界传入的所有数据都添加get/set方法,第二步就是在第一步的基础上,给所有属性都添加观察者对象,当数据发生变化时,发布订阅触发观察者对象的回调函数重新渲染界面。
先处理下 v-model 的情况,找到 CompilerUtil 中的 model 方法,将其修改添加观察者对象代码:
model: function (node, value, vm) {
// 第二部:在第一次渲染的时候, 就给所有的属性添加观察者
new Watcher(vm, value, (newValue, oldValue) => {
node.value = newValue;
});
node.value = this.getValue(vm, value);
},
这样就完成了第二步,接下来第三步就是将当前属性的所有观察者对象都放到当前属性的发布订阅对象中管理起来
在创建观察者对象的时候,在构造函数当中,会调用 getOldValue 方法,会调用 CompilerUtil.getValue 方法,这个方法就是用于获取属性值的,在编译模板之前已经给所有属性添加了 get/set 方法,所以在获取属性值的时候,就会触发 get 方法,我们就可以在 get 方法中将当前属性的观察者对象添加到当前属性的发布订阅对象中管理起来。
在 Observer 类中的 defineRecative 方法中添加如下代码:
defineReactive(obj, attr, value) {
this.observer(value);
// 第三步:将当前属性的所有观察者对象都放到当前属性的发布订阅对象中管理起来
// 创建属于当前属性的发布订阅对象
let dep = new Dep();
Object.defineProperty(obj, attr, {
get() {
Dep.target && dep.addSub(Dep.target);
return value;
},
set: (newValue) => {
if (value !== newValue) {
this.observer(newValue);
value = newValue;
dep.notify();
console.log('监听到数据的变化, 需要去更新UI');
}
}
})
}
在上述代码中,创建了一个属于当前属性的发布订阅对象,然后在 get 方法中,判断 Dep.target 是否存在,如果存在,就将当前属性的观察者对象添加到当前属性的发布订阅对象中管理起来。Dep.target 就是当前属性的观察者对象,这里该需要在改造一下观察者的类,将观察者对象添加到 Dep.target 中,放在全局中管理起来。等到所有的属性都添加完观察者对象之后,就将 Dep.target 置为 null。
改造观察者类中的 getOldValue 方法, 这样在 get 方法中就可以将当前属性的观察者对象添加到当前属性的发布订阅对象中管理起来了:
getOldValue() {
Dep.target = this;
let oldValue = CompilerUtil.getValue(this.vm, this.attr);
Dep.target = null;
return oldValue;
}
这样就完成了数据驱动界面改变的功能,接下来我们就来测试一下,打开浏览器控制台,更改下数据,看看是否会触发界面的重新渲染,如下图所示:

好了到此为止,我们已经完成了 v-model 数据驱动界面改变的功能。
下面我将以 debugger 的形式来讲解一下整个数据驱动界面改变的过程, 在 defineReactive get 方法中打上断点,如下图所示:

返回浏览器,主要关注调用栈,如下图所示:

自己从下依次往上看,就可以看到整个数据驱动界面改变的过程了,这里我就不一一截图了,大家可以自己去看一下。

如上是 get 方法代码的执行流程,那么 set 的我也可以说明一下,set 方法的 debugger 不是打在 defineReactive 中,而是打在 Watcher 类中的 update 方法中,所执行的回调函数当中,如下图所示:

返回浏览器,打开控制台更改数据触发 set 方法,发布订阅触发 update 方法:

这次也是主要关注调用栈,自己从下依次往上看,就可以看到整个数据驱动界面改变的过程了,这里我就不一一截图了,大家可以自己去看一下,如下图所示:

手撕Vue-数据驱动界面改变中的更多相关文章
- 手撕代码:统计1到n二进制数中1出现的总次数
题目描述: 互娱手撕代码题. 统计从1到n这n个数的二进制表示中1出现的次数. 思路分析: 思路一:直接的做法是从1遍历到n,对于每个数和1做与操作,之后,对于这个数不断做右移操作,不断和1做与操作, ...
- 面试中的MySQL主从复制|手撕MySQL|对线面试官
关注微信公众号[程序员白泽],进入白泽的知识分享星球 前言 作为<手撕MySQL>系列的第三篇文章,今天讲解使用bin log实现主从复制的功能.主从复制也是MySQL集群实现高可用.数据 ...
- 如何在vue单页应用中使用百度地图
作为一名开发人员,每次接到开发任务,我们首先应该先分析需求,然后再思考技术方案和解决方案.三思而后行,这是一个好的习惯. 需求:本项目是采用vue组件化开发的单页应用项目,现需要在项目中引入百度的地图 ...
- 手撕公司SSO登陆原理
Single Sign-on SSO是老生常谈的话题了,但部分同学对SSO可能掌握的也是云里雾里,一知半解.本次手撕公司的SSO登陆原理,试图以一种简单,流畅的形式为你提供 有用的SSO登陆原理. 按 ...
- Netty实现高性能IOT服务器(Groza)之手撕MQTT协议篇上
前言 诞生及优势 MQTT由Andy Stanford-Clark(IBM)和Arlen Nipper(Eurotech,现为Cirrus Link)于1999年开发,用于监测穿越沙漠的石油管道.目标 ...
- 模拟源码深入理解Vue数据驱动原理(1)
Vue有一核心就是数据驱动(Data Driven),允许我们采用简洁的模板语法来声明式的将数据渲染进DOM,且数据与DOM是绑定在一起的,这样当我们改变Vue实例的数据时,对应的DOM元素也就会改变 ...
- NN入门,手把手教你用Numpy手撕NN(一)
前言 这是一篇包含极少数学推导的NN入门文章 大概从今年4月份起就想着学一学NN,但是无奈平时时间不多,而且空闲时间都拿去做比赛或是看动漫去了,所以一拖再拖,直到这8月份才正式开始NN的学习. 这篇文 ...
- 理解vue数据驱动
vue是双向数据绑定的框架,数据驱动是他的灵魂,他的实现原理众所周知是Object.defineProperty方法实现的get.set重写,但是这样说太牵强外门了.本文将宏观介绍他的实现 使用vue ...
- 编译原理--05 用C++手撕PL/0
前言 目录 01 文法和语言.词法分析复习 02 自顶向下.自底向上的LR分析复习 03 语法制导翻译和中间代码生成复习 04 符号表.运行时存储组织和代码优化复习 05 用C++手撕PL/0 在之前 ...
- 剖析手写Vue,你也可以手写一个MVVM框架
剖析手写Vue,你也可以手写一个MVVM框架# 邮箱:563995050@qq.com github: https://github.com/xiaoqiuxiong 作者:肖秋雄(eddy) 温馨提 ...
随机推荐
- Java 获取当前天是一年中的第几天
Java 获取当前天是一年中的第几天 @Test void dayofweed() throws Exception { System.out.println("2023-01-01 第 & ...
- 飞书接入ChatGPT
飞书接入ChatGPT 前天我用飞书接入了GPT-3,现在终于可以在国内畅通地聊天了. 上面是群聊截图,下面是私聊截图 其实实现过程极其简单,但是我和好兄弟确实绕了不少弯路. 首先提醒: 1 不适合个 ...
- [VS Code] 入门-自定键盘快捷键
Keyboard Shortcuts 自訂鍵盤快捷鍵 開啟設定面板 :點擊左下角管理圖示〉選擇「鍵盤快速鍵」. 編輯器開啟後,滑鼠移至變更項目上,點擊出現的變更圖示(橘框處),輸入要變更的快捷鍵組合. ...
- (组合游戏)SG函数与SG定理详解
有一段时间没记录知识类的博客了,这篇博客就说一下SG函数和SG定理吧 SG函数是用于解决博弈论中公平组合游戏(Impartial Combinatorial Games,ICG)问题的一种方法. 什么 ...
- Educational Codeforces Round 102 Personal Editorial(A~C,max Rating 1500)
1473A. Replacing Elements Rating 800 对数组排序,一旦数组中最大的数即a[n-1]是一个小于或等于d的数,直接输出YES即可,否则运用数组中最小的两个数加和替换最大 ...
- 使用 Serverless Devs 插件快速部署前端应用
作者| 邓超 Serverless Devs 开源贡献者 背景 我们在 上文 [Aliyun] [FC] 如何使用 @serverless-devs/s 部署静态网站到函数计算 中,详细的介绍了如何通 ...
- IDE暗黑主题推荐-Dracula
作为程序员,我们一天中会花费大量时间在编码和阅读代码上.优秀的代码编辑器主题可以减轻眼睛的疲劳,提高工作效率.本文向大家推荐一款非常流行的 JetBrains IDE 主题插件 - Dracula.它 ...
- go 接口学习笔记
这里是对接口在汇编层面上转换和实现的小结,详细了解可参考 Go 语言接口的原理 1. 类型转换:结构体到接口 1.1 结构体方法实现接口 package main type Duck interfac ...
- mysql 复制表结构创建表及复制表结构与数据创建表
本文为博主原创,未经允许不得转载: 在开发过程或项目维护发布过程中,经常需要复制建表及复制表数据建表等,整理了以下四种常用的 mysql 命令. 1. create like 复制表结构(包含索引, ...
- DC-设计和工艺数据-02
在 compile之前保存ddc设计文件 check design - 检查文件的连接性和物理性 check design之后可以将未映射的网表写出,如果是几十万级的RTL,如果不写出,设置约束出现问 ...