Vue 中使用事件总线来进行组件间通信($emit()、$on() 和 $off())

使用场景:

上一篇文章中写到的:
echarts图表左击显示自定义弹框,右击取消自定义弹框

结构图:(removet修改为remove)

假设这个echarts图表是子组件B页面中。而父页面A的自定义弹框标签里调用了子组件B,(v-if判断)当弹框为true时显示子组件B,反之不显示子组件B(没有dom元素);在子组件B中,需要得知父页面A的弹框是否被关闭,才能将子组件里createElement的弹框元素清除。

所以,通过子组件props获取值且在watch监听父页面A的弹框的状态是行不通的,因为在 Vue 中使用 v-if 来判断是否显示某个元素时,当条件为 false 时,对应的 DOM 元素会被移除,这意味着在页面渲染时,如果 v-if 的条件为 false,相关的 DOM 结构将不会存在于最终的渲染结果中,因此子组件B只能监听到父页面A弹框为显示(true)。

但我们需要的是父页面A弹框为隐藏(false)状态时,移除子组件B中的弹框B。

目录

vue组件通信方法

官网api文档:点击跳转至vue组件事件的中文官网

$emit

$emit(eventName, ...args):用于在当前实例上触发事件。它接收一个事件名称 eventName 作为第一个参数,可以传递额外的参数作为事件回调函数的参数。当调用 $emit() 方法时,会触发相应的事件,并将参数传递给监听该事件的处理函数。

$on

$on(eventName, callback):用于监听当前实例上的事件。当对应的事件被触发时,注册的回调函数 callback 将会被调用。可以通过 $on() 方法来绑定事件监听器。

$off

$off(eventName, callback):用于移除事件监听器。可以通过 $off() 方法来解绑先前使用 $on() 绑定的事件监听器。如果提供了 eventName 参数,则只会移除该事件相关的监听器;如果同时提供了 eventName 和 callback 参数,则只会移除指定事件及回调函数的监听器。

其它vue方法(本文没使用到的)

$watch():用于侦听 Vue 实例上的数据变化并做出相应的响应。

$nextTick():用于在 DOM 更新之后执行延迟回调函数。

$refs:用于访问子组件或子元素的引用。

this. $ router 和 this. $ route:用于访问 Vue Router 的路由实例和路由信息对象。

示例:

javascript 复制代码
created() {
	this.$watch("searchdata.isasc", this.handleIsAscChange);
}

逻辑分析

子组件 B 能够在弹框状态为 false 时也能监听到父页面 A 的弹框关闭状态,这就需要使用事件总线来实现,在 Vue 应用中创建一个事件总线 bus,并在父页面 A 中发送事件,子组件 B 监听这个事件来获取父页面弹框状态的变化。

全局挂载

在 main.js 中创建事件总线 bus:

javascript 复制代码
import Vue from 'vue';
export const bus = new Vue();

父页面

父页面 A 中发送事件:

javascript 复制代码
<template>
  <div class="bigbox-class">
    <el-button type="primary" @click="openClick">显示弹框</el-button>
    <!-- 弹框部分 -->
    <div class="alert-modal-container alertbox" v-if="showModal">
      <div class="alert-modal-shadow"></div>
      <div class="alert-modal-content">
        <div class="alert-modal-header">
          <span>{{ title }}</span>
          <button @click="closeClick">×</button>
        </div>
        <div class="alert-modal-body">
          <line-standard-com></line-standard-com>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import LineStandardCom from "./line-Components/lineCom.vue"; //子组件
import { bus } from './main.js';

export default {
  components: { LineStandardCom },
  data() {
    return {
      showModal: false,
      title: "弹框名称",
    };
  },
  methods: {
    closeClick() {
      this.showModal = false;
      bus.$emit("modalStateChanged", false);
    },
    openClick() {
      this.showModal = true;
      bus.$emit("modalStateChanged", true);
    },
  }
};
</script>

子组件

监听事件

在子组件 B 中监听事件:

javascript 复制代码
<template>
  <div>
    <!-- 子组件的内容,即上篇文章写到的echarts图表创建弹框元素内容 -->
  </div>
</template>

<script>
import "./lineStyle.css";//样式页面
import { bus } from './main.js';

export default {
  created() {
    bus.$on('modalStateChanged', (showModal) => {
      console.log("showModal", showModal);
      if (!showModal) { //父组件A的弹框隐藏(false)时
        console.log('Modal in parent component is closed');
      }
    });
  },
};
</script>

解绑监听事件

上面$on()方法监听方法中输出可以得出,每一次变化弹框状态时,输出showModal次数会递增,意味着会出现内存泄漏或不必要的性能消耗。

所以在每次组件销毁或离开时,建议及时解绑事件监听。可以在子组件的 beforeDestroy 生命周期钩子中,使用 bus. $off 来解绑事件监听,以确保不会产生不必要的内存消耗。

javascript 复制代码
<script>
import { bus } from './main.js';

export default {
  created() {
    bus.$on('modalStateChanged', this.handleModalStateChange);
  },
  beforeDestroy() {
    bus.$off('modalStateChanged', this.handleModalStateChange);
  },
  methods: {
    handleModalStateChange(showModal) {
      if (!showModal) { //父组件A的弹框隐藏(false)时
        if (this.currentMenu && this.currentMenu.parentNode === document.body) {
          document.body.removeChild(this.currentMenu); // 清除子组件B弹框的菜单元素
        }
      }
    },
  }
};
</script>
相关推荐
customer0823 分钟前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
清灵xmf24 分钟前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据30 分钟前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_3901617739 分钟前
防抖函数--应用场景及示例
前端·javascript
334554321 小时前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test1 小时前
js下载excel示例demo
前端·javascript·excel
Yaml41 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事1 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶1 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo1 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx