js中事件绑定3种方法以及事件委托_从观察者模式与发布-订阅模式到双向数据绑定简单实现...

本文对比了观察者模式和发布-订阅模式,指出二者都是数据变化时更新状态的模式,发布-订阅模式多了事件中心,解耦度更高。还分析了Vue依赖收集倾向于观察者模式,最后用发布-订阅模式简单实现了数据绑定功能,加深了对Vue数据绑定的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.背景

平时使用过 Vue 这个前端框架的同学,对于数据绑定这个词肯定不会陌生,进一步,它与 react 有点不同的是它还有一个双向数据绑定 v-model

数据绑定的方式能够极大程度上方便我们开发,不用去进行繁琐的 DOM 操作,这也是 MVVM 框架的一个极大的优势所在。

网上阅读到其他同学对 Vue 源码解读的文章,发现大家对 Vue 的依赖收集机制解读会有些不一样的方式。有些同学解释说依赖收集使用的观察者模式,有些同学则解释说是发布/订阅模式

因为以前认为这两个名字只是不同的叫法而已也就没太在意,但偶然发现有人问这两个模式的区别,这个问题突然也引起了我的好奇心,因此也就花了些时间来比较这两个名词背后到底有什么不同。

49ddb3ab8280713bd2473f961e9db03d.png

2.两个模式的异同

2b184219dc86ebf892df08efebc4f5c5.png

观察者模式与发布-订阅模式

首先直接上图。从图中可以看出,无论是观察者模式还是发布-订阅模式,它们都是一些状态依赖于某些数据,当数据发生变化,这些状态也需要进行相应的更新的模式。不同点在于,发布-订阅模式比观察者模式多了个事件中心

更细致点说,在观察者模式中,被观察者能够完全感知到观察者的存在,一旦发生变化,被观察者负责将变化通知到所有的观察者。

举个例子,假设你要出租一套房子,你在网上发布了信息,有很多人联系你。当你的房子租出去之后,你要将这个信息通知到剩下的其他人,让他们去租别的房子。

5982195a164bfd8615f6c56eea03fc3f.png

而在发布-订阅模式中,因为有个事件中心的存在,当发布者发布新的信息之后,事件中心会去通知更新。

还是出租房子的例子,你把你要出租房子的信息告诉中介,同时中介那边有很多客户让中介帮忙找房,当你的房子租出去后,你只需要告诉中介房源没了,中介则会去通知意向客户房源缺失的信息。

在该模式中,订阅者向事件中心订阅某些事件,发布者并不知道有没有订阅者,只要发生变化,发布者就会通知事件中心。

下面就用实际的代码来还原一下这两个模式。

3.观察者模式

ObserverList.js

观察者列表类,由被观察者管理,添加或移除对应的观察者。

89dfea2b5f2ad9e3bf23ae35ce7a3238.png
Observer.js

观察者类,接到更新通知后,做出一些反馈。

6ed5f949245ca2068c1885b3ab671d99.png
Observed.js

被观察者类,负责维护观察者,并且将更新通知到所有观察者。

4c6568e3be7c80d9cb6fff4f0d20c582.png
index.js
0ca985c288667895f3592ec9bae58717.png

4.发布-订阅模式

EventCenter.js

事件中心类,包括处理订阅者的订阅/退订事件,以及发布者发布事件后的变更通知。

de96b9e0a75a7a2c018a09fb15a54613.png
Publisher.js

发布者类,负责向事件中心发布变更。

c9a7f5fde0ad09a94a015c5838104f9d.png
Subscriber.js

订阅者类,对变更通知做出反馈。

56b4863216352ad092817ed4ce1ed818.png
index.js
f50555d7b1a83caa3448c37e99d8fa40.png

5.小结

总的来说,两种设计模式都是为了解耦,其中发布-订阅模式解耦度更高。也可以认为发布-订阅模式是观察者模式的进一步解耦,这也是有时候会认为这两个模式一样。

现在反过来看 Vue 中的依赖搜集,它更多的倾向于观察者模式,因为对于某个数据的观察,拥有该数据的对象都能清楚的感知,当数据变化后,它都要通知到各个依赖对象。

有人认为观察者模式更多的是同步操作,而发布-订阅模式更适合异步操作(引入消息队列),但就 Vue 来说,它在派发更新过程中,也引入了队列的概念,Vue 并不是每当数据更新就立马响应,而是放入一个队列,在下一个 Tick 中再将该队列整个刷新。

6.用发布-订阅模式实现数据绑定

既然前面已经知道 Vue 是通过观察者模式来实现依赖收集的,那这里就用发布-订阅模式来简单实现一下数据绑定的功能!

40886900e1360b9274a97772480232a6.png

说干就干!

先让我们来分析一下做这个例子的流程。

1、首先,我们需要一个事件中心eventCenter,能够满足 DOM 节点对响应式数据变化的订阅,能够在数据变化后发布信息给 DOM 节点。

2、其次,我们需要对所有的响应式数据进行拦截,用Object.defineProperty方法进行改写,主要是在set函数中通过事件中心发布变化。

最后,我们需要对管理的 DOM 节点进行遍历,将{{ 响应式变量 }}替换为实际数据,并且对数据进行变更订阅。

既然流程搞清楚了,那就开始撸代码吧!

Coding…

  • eventCenter.js
e44a05c8fe8d414f76e8c35b1a9b3a62.png
  • dataBinding.js
a3c0b724574109bbdbd201bfa1f8af82.png
  • index.html
28c7500018d53c105d685c75789a8ffc.png

eventCenter.js就是事件处理中心,dataBinding.js就是完成数据绑定的主要逻辑操作了。

在遍历所有 DOM 节点的时候,对于文本节点,用正则表达式判断是否引用响应式数据,如果有则进行相应的替换,对于标签节点,首先判断是不是input节点,因为需要对v-model做双向绑定操作,然后再通过递归进行子节点的筛选。

结果演示

0dc1eca79c6f7fe29655f625dcd13c7e.gif

相较于 Vue 的实际数据绑定的实现,这个 demo 肯定是极其简略甚至粗糙的(╭(╯^╰)╮)~比如说,一个标签节点中既有普通文本,又有响应式数据,或者一个标签里有多个数据绑定,这些都没处理。

但通过这个简单的例子,加深了自己对于 Vue 数据绑定的理解还是很有意义的~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值