实现简易vue响应式
实现简易vue响应式
Author: huyikai
1.defineProperty 的应用
在Vue2.X 响应式中使用到了 defineProperty 进行数据劫持,所以我们对它必须有一定的了解,那么我们先来了解它的使用方法把, 这里我们来使用 defineProperty来模拟 Vue 中的 data
可以看见 上面 vm.msg 数据是响应式的
2.defineProperty修改多个参数为响应式
修改多个参数
看了上面的方法只能修改一个属性,实际上我们 data 中数据不可能只有一个,我们何不定义一个方法把data中的数据进行遍历都修改成响应式呢
3.Proxy
在Vue3 中使用 Proxy 来设置响应式的属性
先来了解下 Proxy 的两个参数
target
:要使用 Proxy
包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
handler
:一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p
的行为
其实 和 Vue2.X实现的逻辑差不多,不过实现的方法不一样
那么就放上代码了
触发set 和 get 的方法
4.发布订阅模式
在Vue 响应式中应用到了 发布订阅模式 我们先来了解下
首先来说简单介绍下 一共有三个角色
发布者、 订阅者、 信号中心 举个现实中例子 作者(发布者)写一篇文章 发到了掘金(信号中心) ,掘金可以处理文章然后推送到了首页,然后各自大佬(订阅者)就可以订阅文章
在Vue 中的例子 就是EventBus $on
$emit
那么我们就简单模仿一下 Vue 的事件总线吧
之前代码缩进4个单位有点宽,这里改成2个
5.观察者模式
与 发布订阅 的差异
与发布订阅者不同 观察者中 发布者和订阅者(观察者)是相互依赖的 必须要求观察者订阅内容改变事件 ,而发布订阅者是由调度中心进行调度,那么看看观察者模式 是如何相互依赖,下面就举个简单例子
6.模拟Vue的响应式原理
这里来实现一个小型简单的 Vue 主要实现以下的功能
- 接收初始化的参数,这里只举几个简单的例子 el data options
- 通过私有方法 _proxyData 把data 注册到 Vue 中 转成getter setter
- 使用 observer 把 data 中的属性转为 响应式 添加到 自身身上
- 使用 observer 方法监听 data 的所有属性变化来 通过观察者模式 更新视图
- 使用 compiler 编译元素节点上面指令 和 文本节点差值表达式
1.vue.js
在这里获取到 el
data
通过 _proxyData 把 data的属性 注册到Vue 并转成 getter setter
2.observer.js
在这里把 data 中的 属性变为响应式加在自身的身上,还有一个主要功能就是 观察者模式在 第 4.dep.js
会有详细的使用
在html中引入的话注意顺序
然后在vue.js 中使用 Observer
看到这里为什么做了两个重复性的操作呢?重复性两次把 data的属性转为响应式
在obsever.js 中是把 data 的所有属性 加到 data 自身 变为响应式 转成 getter setter方式
在vue.js 中 也把 data的 的所有属性 加到 Vue 上,是为了以后方面操作可以用 Vue 的实例直接访问到 或者在 Vue中使用 this 访问
使用例子
这样在Vue
和 $data
中都存在了 所有的data 属性了 并且是响应式的
3.compiler.js
comilper.js在这个文件里实现对文本节点 和 元素节点指令编译 主要是为了举例子 当然这个写的很简单 指令主要实现 v-text v-model
4.dep.js
写一个Dep类 它相当于 观察者中的发布者 每个响应式属性都会创建这么一个 Dep 对象 ,负责收集该依赖属性的Watcher对象 (是在使用响应式数据的时候做的操作)
当我们对响应式属性在 setter 中进行更新的时候,会调用 Dep 中 notify 方法发送更新通知
然后去调用 Watcher 中的 update 实现视图的更新操作(是当数据发生变化的时候去通知观察者调用观察者的update更新视图)
总的来说 在Dep(这里指发布者) 中负责收集依赖 添加观察者(这里指Wathcer),然后在 setter 数据更新的时候通知观察者
说的这么多重复的话,大家应该知道是在哪个阶段 收集依赖 哪个阶段 通知观察者了吧,下面就来实现一下吧
先写Dep类
在 obsever.js 中使用Dep
在 get 中添加 Dep.target (观察者)
在 set 中 触发 notify (通知)
5.watcher.js
**watcher **的作用 数据更新后 收到通知之后 调用 update 进行更新
那么去哪里创建 Watcher 呢?还记得在 compiler.js中 对文本节点的编译操作吗
在编译完文本节点后 在这里添加一个 Watcher
还有 v-text v-model 指令 当编译的是元素节点 就添加一个 Watcher
当 我们改变 响应式属性的时候 触发了 set() 方法 ,然后里面 发布者 dep.notify 方法启动了,拿到了 所有的 观察者 watcher 实例去执行 update 方法调用了回调函数 cb(newValue) 方法并把 新值传递到了 cb() 当中 cb方法是的具体更新视图的方法 去更新视图
比如上面的例子里的第三个参数 cb方法
还有一点要实现v-model的双向绑定
不仅要通过修改数据来触发更新视图,还得为node添加 input 事件 改变 data数据中的属性
来达到双向绑定的效果
7.测试下自己写的
到了目前为止 响应式 和 双向绑定 都基本实现了 那么来写个例子测试下
这样基本实现了 通过 观察者模式 来 实现 响应式原理
8.五个文件代码
这里直接把5个文件个代码贴出来 上面有的地方省略了,下面是完整的方便大家阅读
vue.js
obsever.js
compiler.js
dep.js
watcher.js