详解利用eventemitter2实现Vue组件通信


Posted in Javascript onNovember 04, 2019

概述

当两个组件之间没有任何父子关系时,利用Vue标准的props传值和emit触发事件无法解决他们之间通信的问题。最近做的项目使用的是eventemitter2,来实现不相关组件之间的通信。这篇文章分享的是我对eventemitter2使用的总结和体会。

eventemitter2的npm文档大家可以看eventemitter2介绍。它是node.js提供的事件接口。安装如下

npm install --save eventemitter2

模块的EventEmitter2属性是一个构造函数,可以生成eventemitter2实例。实例定义了绑定、触发、移除事件的方法。本文涉及到的实例方法有on,off,emit,removeAllListeners,更多方法,大家可以去npm文档自行学习。

和其他事件处理机制一样,eventemitter2事件处理,必须包含三部分:
绑定事件 =》 触发事件 =》 移除事件

本次分享,主要讨论在vue项目中使用eventemitter2:

  • 方法一:结合class模块化编程,对实例、事件名、绑定事件方法和移除事件方法做封装
  • 方法二:结合vue插件开发,全局添加事件实例

方法一:结合class

开发步骤:

  • 添加模块 event_confg.js,用于存储eventEmitter2实例和事件名
  • 添加模块 event_manager.js,封装实例绑定事件的方法和移除事件的方法
  • 按照 绑定事件 =》 触发事件 =》 移除事件的步骤,使用eventeitter2

第一步:创建 event_confg.js

var EventEmitter2 = require('eventemitter2').EventEmitter2;
// emiter中定义的是eventemitter2实例,config中定义的是事件名
const eventConfig = {}

eventConfig.emitter = new EventEmitter2()

eventConfig.config = {
 "CHECK_CHANGES": "checkChanges"
 // 更多的事件名,往这里添加
}
export default eventConfig

第二步: 创建event_manager.js

此模块创建的是一个类,传入eventemitter2实例后,对实例的添加和移除事件的方法做了封装。

这里绑定和移除事件,分别用了on,off方法。

export default class {
  constructor(evtInst){
    this.evtInst = evtInst
    this.listeners = {} // {eventName: [callback1,callback2...]}
  }
  // 将事件名evtName的回调绑定为callback,同时将事件名和回调存到listeners,方便后面移除事件使用
  addListener(evtName, callback){
    this.evtInst.on(evtName, callback)
    if(!this.listeners[evtName]){
      this.listeners[evtName] = [callback]
    }else{
      this.listeners[evtName].push(callback)
    }
  }
  removeListeners(){
    Object.keys(this.listeners).forEach(evtName => {
      this.listeners[evtName].forEach((callback, index) => {
        this.evtInst.off(evtName,callback)
      })
    })
  }
}

第三步: 在组件中使用eventemitter2

绑定事件

同一个事件名,可以绑定多个事件回调,当事件被触发时,会顺序执行同名的回调函数

import EventManager from "@/utils/event_manager.js"
import eventConfig from "@/utils/event_config.js"
...
// 初始化event_manager实例
this.evtManagerInst = new EventManager(eventConfig.emitter)
// 用实例的addListener方法绑定事件
this.evtManagerInst.addListener(eventConfig.config.CHECK_CHANGES, obj => {
  this.value = Object.is(NaN,parseInt(obj.value))
})
this.evtManagerInst.addListener(eventConfig.config.CHECK_CHANGES, obj => {
  console.log("第二个事件也触发了!",obj)
})

触发事件

事件的触发和回调是同步执行的。用下面的方式触发事件后,执行的过程是:

打印 准备触发啦! =》 执行回调 =》 执行 $message弹框

import eventConfig from "@/utils/event_config.js"
...
// 传给事件回调函数的参数
let obj = {value: val, type: "", msg: ""}
// 触发事件
console.log("准备触发啦!")
eventConfig.emitter.emit(eventConfig.config.CHECK_CHANGES, obj)
// 事件触发后的处理
this.$message({type: obj.type, message: obj.msg})

移除事件

在beforeRouteLeave或者beforeDestory中移除事件

如果使用的是beforeRouteLeave注意调用它的next函数,让路由继续往下执行

beforeDestroy(){
  this.evtManagerInst.removeListeners()
}

方法二:结合Vue插件开发

思路是,向顶层Vue对象添加全局的eventemitter2对象作为属性。

开发步骤:

  1. 使用install创建emitter.js插件,在其中给Vue添加全局属性
  2. 使用全局的Vue.use()方法,使用插件
  3. 按照 绑定事件 =》 触发事件 =》 移除事件的步骤,使用eventeitter2

第一步:创建全局变量

添加全局属性$emit_inst,存储实例;添加全局的$emit_name,存储事件名

var EventEmitter2 = require('eventemitter2').EventEmitter2;

// 事件名,实例
const emitter = {}

// 创建实例,定义事件名
emitter.install = function(Vue){
 Vue.prototype.$emit_inst = new EventEmitter2()
 Vue.prototype.$emit_name = {
  "CHECK_TYPE_TWO": "checkTypeTwo",
  "ANOTHER_EVENT": "anotherEvt"
  // 继续往后添加实例名
 }
}
export default emitter

第二步:使用插件

在main.js中,new Vue()命令创建实例之前,调用Vue.use()方法,使用插件

import emitter from "./emitter"
Vue.use(emitter)

第三步:在组件中使用eventemitter2

绑定事件

这里使用的是,官方文档的on方法,传入eventName和回调,给实例绑事件,并定义回调函数。
同一个事件名,可以绑定多个事件回调,当事件被触发时,会顺序执行同名的回调函数

this.$emit_inst.on(this.$emit_name.CHECK_TYPE_TWO, obj => {
  this.value1 = Object.is(NaN,parseInt(obj.value))
  obj.type = this.value1 ? "success" : "warning"
  obj.msg = this.value1 ? "字符" : "数字"
  console.log("CHECK_TYPE_TWO第一次触发")
})
this.$emit_inst.on(this.$emit_name.CHECK_TYPE_TWO, obj => {
  console.log("CHECK_TYPE_TWO第二次触发")
})

触发事件

事件的触发和回调是同步执行的。执行过程,上面有说明。

this.$emit_inst.emit(this.$emit_name.CHECK_TYPE_TWO, obj)

移除事件

直接在实例上移除事件时,使用removeAllListeners方便,因为只用传事件名。

beforeDestroy(){
  this.$emit_inst.removeAllListeners(this.$emit_name.CHECK_TYPE_TWO)
}

总结:

使用eventemitter2,就是正确创建实例,给实例绑定、触发和移除事件。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 异步调用框架 (Part 1 - 问题 & 场景)
Aug 03 Javascript
jQuery学习5 jQuery事件模型
Feb 07 Javascript
javascript 防止刷新,后退,关闭
Aug 07 Javascript
jQuery实现为控件添加水印文字效果(附源码)
Dec 02 Javascript
JS实现支持Ajax验证的表单插件
Mar 24 Javascript
AngularJs  Using $location详解及示例代码
Sep 02 Javascript
AngularJS equal比较对象实例详解
Sep 14 Javascript
BootStrap整体框架之基础布局组件
Dec 15 Javascript
chorme 浏览器记住密码后input黄色背景处理方法(两种)
Nov 22 Javascript
Vue配合iView实现省市二级联动的示例代码
Jul 27 Javascript
JS实现的检验身份证格式并输出出生日期,年龄,性别,出生地示例
May 17 Javascript
js实现无缝轮播图插件封装
Jul 31 Javascript
jQuery实现form表单基于ajax无刷新提交方法实例代码
Nov 04 #jQuery
JS立即执行的匿名函数用法分析
Nov 04 #Javascript
小程序如何自主实现拦截器的示例代码
Nov 04 #Javascript
uni-app微信小程序登录并使用vuex存储登录状态的思路详解
Nov 04 #Javascript
JavaScript判断浏览器版本的方法
Nov 03 #Javascript
JavaScript算法学习之冒泡排序和选择排序
Nov 02 #Javascript
如何正确理解vue中的key详解
Nov 02 #Javascript
You might like
提问的智慧(2)
2006/10/09 PHP
PHP把MSSQL数据导入到MYSQL的方法
2014/12/27 PHP
屏蔽PHP默认设置中的Notice警告的方法
2016/05/20 PHP
Yii2使用自带的UploadedFile实现的文件上传
2016/06/20 PHP
phpStudy中升级MySQL版本到5.7.17的方法步骤
2017/08/03 PHP
PHP实现上传图片到数据库并显示输出的方法
2018/05/31 PHP
两个listbox实现选项的添加删除和搜索
2013/03/01 Javascript
JavaScript按值删除数组元素的方法
2015/04/24 Javascript
JavaScript实现节点的删除与序号重建实例
2015/08/05 Javascript
jquery图片倾斜层叠切换特效代码分享
2015/08/27 Javascript
在JavaScript中call()与apply()区别
2016/01/22 Javascript
AngularJS入门教程之过滤器详解
2016/08/19 Javascript
jQuery图片轮播(二)利用构造函数和原型创建对象以实现继承
2016/12/06 Javascript
jQuery Ajax File Upload实例源码
2016/12/12 Javascript
smartupload实现文件上传时获取表单数据(推荐)
2016/12/12 Javascript
Javascript中绑定click事件的四种方式介绍
2018/10/26 Javascript
JavaScript数据结构与算法之二叉树插入节点、生成二叉树示例
2019/02/21 Javascript
使用Python保存网页上的图片或者保存页面为截图
2016/03/05 Python
详解Python之数据序列化(json、pickle、shelve)
2017/03/30 Python
NetworkX之Prim算法(实例讲解)
2017/12/22 Python
python中logging模块的一些简单用法的使用
2019/02/22 Python
对python中UDP,socket的使用详解
2019/08/22 Python
Python通过Tesseract库实现文字识别
2020/03/05 Python
如何查看python关键字
2021/01/17 Python
html5 浏览器支持 如何让所有的浏览器都支持HTML5标签样式
2012/12/07 HTML / CSS
加拿大当代时尚服饰、配饰和鞋类专业零售商和制造商:LE CHÂTEAU
2017/10/06 全球购物
美国领先的眼镜和太阳镜在线零售商:Glasses.com
2019/08/26 全球购物
生物技术毕业生自荐信
2013/10/23 职场文书
医学专业毕业生推荐信
2013/11/14 职场文书
营销总经理的岗位职责
2013/12/15 职场文书
公司节能减排倡议书
2014/05/14 职场文书
放飞梦想演讲稿600字
2014/08/26 职场文书
毕业生自荐信范文
2015/03/05 职场文书
电影红河谷观后感
2015/06/11 职场文书
小学中队委竞选稿
2015/11/20 职场文书
MySQL一劳永逸永久支持输入中文的方法实例
2022/08/05 MySQL