资讯专栏INFORMATION COLUMN

手写一个EventBus事件处理中心(解读vue的事件方法)

VPointer / 3520人阅读

摘要:中的事件相关的方法扒一扒的源码,中事件相关的方法,无非这几个,。通过方法挂在的原型上,本文就是通过解读的源码,实现一个简单的事件处理中心类。全局定义一个属性,存储事件通过方法在的原型上挂载方法接下来,我们来实现方法。

vue中的事件相关的方法

扒一扒Vue的源码,vue中事件相关的方法,无非这几个,vm.$on, vm.$off, vm.$once, vm.$emit。通过eventsMinxin方法挂在Vue的原型上,本文就是通过解读vue的源码,实现一个简单的事件处理中心类 EventBus。

首先,我们来回顾下这几个方法的用法:

vm.$on( event, callback )

参数:

{string | Array} event (数组只在 2.2.0+ 中支持)

{Function} callback

vm.$once( event, callback )

参数:

{string} event

{Function} callback

vm.$off( [event, callback] )

参数:

{string | Array} event (只在 2.2.2+ 支持数组)

{Function} [callback]

vm.$emit( eventName, […args] )

参数:

{string} eventName

[...args]

触发当前实例上的事件。附加参数都会传给监听器回调。

实现一个EventBus

首先,我们先定义一个全局的类EventBus。

</>复制代码

  1. function EventCenter() {
  2. // 全局定义一个_events属性,存储事件
  3. this._events = Object.create(null);
  4. }
  5. // 通过eventMixin方法在EventCenter的原型上挂载方法
  6. eventMixin(EventCenter);
  7. export default EventCenter;

接下来,我们来实现eventMixin方法。

</>复制代码

  1. export default function eventMixin(EventCenter) {
  2. EventCenter.prototype.on = function(event, fn) {...}
  3. EventCenter.prototype.off = function(event, fn) {...}
  4. EventCenter.prototype.once = function(event, fn) {...}
  5. EventCenter.prototype.once = function(event) {...}
  6. }

ec.on( event, fn ), event值可以为数组和字符串,fn为事件触发时的回调函数

</>复制代码

  1. EventCenter.prototyoe.on = function(event, fn) {
  2. const ec = this;
  3. if (Array.isArray(event)) {
  4. for (let i = 0; i < event.length; i++) {
  5. ec.on(event[i], fn)
  6. }
  7. } else {
  8. (ec._events[event] || (ec._events[event] = [])).push(fn);
  9. }
  10. }

ec.off( event, fn ), event值可以为数组和字符串,fn为事件触发时的回调函数

</>复制代码

  1. EventCenter.prototyoe.on = function(event, fn) {
  2. const ec = this;
  3. // 判断如果不传参数, 则移除所有事件
  4. if (!arguments.length) {
  5. ec._events = Object.create(null);
  6. }
  7. // event为数组时,遍历移除事件
  8. if (Array.isArray(event)) {
  9. for(let i = 0; i < event.length; i++) {
  10. ec.off(event[i], fn);
  11. }
  12. return ec;
  13. }
  14. const cbs = ec._events[event];
  15. // 回调不存在 直接返回
  16. if (!cbs) {
  17. return ec;
  18. }
  19. // cbs为一个或者fn不存在,ec._events[event] = null, 直接移除
  20. if (arguments.length === 1) {
  21. ec._events[event] = null;
  22. return ec;
  23. }
  24. if (!fn) {
  25. ec._events[event] = null;
  26. return ec;
  27. }
  28. // 否则,遍历cbs,移除cbs中为fn的回调函数
  29. let cb;
  30. let i = cbs.length;
  31. // 从后向前遍历,移除当前监听器时,不会影响未遍历过的监听器的位置。
  32. while (i--) {
  33. cb = cbs[i];
  34. if (cb === fn || cb.fn === fn) {
  35. cbs.splice(i, 1);
  36. break;
  37. }
  38. }
  39. return ec;
  40. }

ec.once( event, fn ), event值可以为字符串,fn为事件触发时的回调函数

</>复制代码

  1. const ec = this;
  2. // 自定义一个_on方法,先解绑_on, 然后通过调用apply方法执行fn。
  3. function _on() {
  4. ec.off(event, _on);
  5. fn.apply(ec, arguments);
  6. }
  7. // 这句暂时没看懂,等之后查了资料补充
  8. _on.fn = fn;
  9. ec.on(event, _on);
  10. return ec;

ec.emit( event, ...args ), event值可以为字符串,...args为调用时的传参

</>复制代码

  1. EventCenter.prototype.emit = function(event) {
  2. const ec = this;
  3. let cbs = ec._events[event];
  4. if (cbs) {
  5. // 拿到传参
  6. const args = Array.from(arguments).slice(1);
  7. for(let i = 0; i < cbs.length; i++) {
  8. try {
  9. cbs[i].apply(ec, args);
  10. } catch(e) {
  11. new Error("error");
  12. }
  13. }
  14. }
  15. return ec;
  16. }

至此,一个简单的事件中心就完成了。

参考: vue源码 core/instance/events.js

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106400.html

相关文章

  • vue中8种组件通信方式, 值得收藏!

    摘要:一父组件通过的方式向子组件传递数据,而通过子组件可以向父组件通信。而且只读,不可被修改,所有修改都会失效并警告。 之前写了一篇关于vue面试总结的文章, 有不少网友提出组件之间通信方式还有很多, 这篇文章便是专门总结组件之间通信的 vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢?首先我们需要知道在vue中组件之间存在什么样...

    BicycleWarrior 评论0 收藏0
  • Vue实践」武装你前端项目

    摘要:所有的高阶抽象组件是通过定义选项来声明的。所以一般在生命周期或者中,需要用实例的方法清除可当你有多个时,就需要重复性劳动销毁这件事儿。更多的配置请看双端开启开启压缩的好处是什么可以减小文件体积,传输速度更快。本文目录 接口模块处理 Vue组件动态注册 页面性能调试:Hiper Vue高阶组件封装 性能优化:eventBus封装 webpack插件:真香 本文项目基于Vue-Cli3,想知...

    曹金海 评论0 收藏0
  • vue非父子组件通信中eventbus被多次触发(vue中使用eventbus踩过坑)

    摘要:主要是看这是从上个页面传来的数据这一行数据的输出次数情况来判断事件触发次数。总结所以,如果想要用来进行页面组件之间的数据传递,需要注意亮点,组件事件应在生命周期内。其次,组件内的记得要销毁。 转载于简书 原文链接:https://www.jianshu.com/p/fde...一开始的需求是这样子的,我为了实现两个页面组件之间的数据传递,假设我有页面A,点击页面A上的某一个按钮之后,页...

    CHENGKANG 评论0 收藏0
  • vue数据传递--我有特殊实现技巧

    摘要:同时有一种特殊的实现方案。组件之间传值有这么几种数据传递方式,和特殊的。在所有实例中使用其进行数据的通信。双多方使用同名事件进行沟通。数据非长效数据,无法保存,只在后生效。这样约定的好处是,我们能够记录所有中发生的改变。 前言 最近碰到了比较多的关于vue的eventBus的问题,之前定技术选型的时候也被问到了,vuex和eventBus的使用范围。所以简单的写一下。同时有一种特殊的实...

    xiaoxiaozi 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<