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>
相关推荐
gnip40 分钟前
链式调用和延迟执行
前端·javascript
SoaringHeart1 小时前
Flutter组件封装:页面点击事件拦截
前端·flutter
杨天天.1 小时前
小程序原生实现音频播放器,下一首上一首切换,拖动进度条等功能
前端·javascript·小程序·音视频
Dragon Wu1 小时前
React state在setInterval里未获取最新值的问题
前端·javascript·react.js·前端框架
Jinuss1 小时前
Vue3源码reactivity响应式篇之watch实现
前端·vue3
YU大宗师1 小时前
React面试题
前端·javascript·react.js
木兮xg1 小时前
react基础篇
前端·react.js·前端框架
ssshooter2 小时前
你知道怎么用 pnpm 临时给某个库打补丁吗?
前端·面试·npm
IT利刃出鞘2 小时前
HTML--最简的二级菜单页面
前端·html
yume_sibai2 小时前
HTML HTML基础(4)
前端·html