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>
相关推荐
rising start16 分钟前
前端基础一、HTML5
前端·html·html5
Never_Satisfied25 分钟前
在JavaScript / HTML中,div容器在内容过多时不显示超出的部分
开发语言·javascript·html
鬼谷中妖26 分钟前
JavaScript 循环与对象:深入理解 for、for...in、for...of、不可枚举属性与可迭代对象
前端
大厂码农老A30 分钟前
你打的日志,正在拖垮你的系统:从P4小白到P7专家都是怎么打日志的?
java·前端·后端
im_AMBER32 分钟前
CSS 01【基础语法学习】
前端·css·笔记·学习
DokiDoki之父36 分钟前
前端速通—CSS篇
前端·css
pixle039 分钟前
Web大屏适配终极方案:vw/vh + flex + clamp() 完美组合
前端·大屏适配·vw/vh·clamp·终极方案·web大屏
ssf19871 小时前
前后端分离项目前端页面开发远程调试代理解决跨域问题方法
前端
@PHARAOH1 小时前
WHAT - 前端性能指标(加载性能指标)
前端
尘世中一位迷途小书童1 小时前
🎨 SCSS 高级用法完全指南:从入门到精通
前端·css·开源