vue3中事件总线
在 Vue 3 中,eventBus 的概念已经被弱,不推荐使用全局事件总线
,
你需要一个轻量级的事件总线,可以自己封装一个 EventBus 类,也有一些替代方案
1、使用第三方库(如 mitt 或 tiny-emitter)
mitt 是一个轻量级的事件发射器,适合在 Vue 3 中替代事件总线。它不依赖 Vue 实例,体积小且易于使用。
npm install mitt
// src/utils/eventBus.js
import mitt from 'mitt';
export const emitter = mitt();
import { emitter } from './utils/eventBus';
// 触发事件
emitter.emit('event-name', data);
// 取消监听
emitter.off('event-name', handler);
2、依赖注入
provide 和 inject 是 Vue 3 推荐的父子组件通信方式,适合在组件树中传递数据。
// 父组件
import { provide } from 'vue';
export default {
setup() {
provide('message', 'Hello from Parent');
}
};
// 子组件
import { inject } from 'vue';
export default {
setup() {
const message = inject('message');
console.log(message);
}
};
3、使用vuex或者pina
对于复杂的状态管理,推荐使用 Vuex 或 Pinia。它们提供了更强大的状态管理能力,适合大型项目。
// store.js
import { createStore } from 'vuex';
export default createStore({
state: {
message: 'Hello from Vuex'
},
mutations: {
updateMessage(state, payload) {
state.message = payload;
}
}
});
import { useStore } from 'vuex';
export default {
setup() {
const store = useStore();
store.commit('updateMessage', 'New Message');
console.log(store.state.message);
}
};
4、使用props和emits
对于父子组件通信,props 和 emits 是最直接的方式。
<template>
<ChildComponent :message="message" @update="handleUpdate" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
message: 'Hello from Parent'
};
},
methods: {
handleUpdate(newMessage) {
this.message = newMessage;
}
}
};
</script>
<template>
<button @click="updateMessage">Update Message</button>
</template>
<script>
export default {
props: ['message'],
emits: ['update'],
methods: {
updateMessage() {
this.$emit('update', 'New Message');
}
}
};
</script>
5、自己封装
在 Vue 3 中,你可以通过创建一个 Vue 实例作为事件总线来实现类似的功能。
// src/eventBus.js
import { createApp } from 'vue';
const eventBus = createApp({});
// 添加自定义事件方法
eventBus.config.globalProperties.$emit = function (event, ...args) {
this._eventBus.emit(event, ...args);
};
eventBus.config.globalProperties.$on = function (event, callback) {
this._eventBus.on(event, callback);
};
eventBus.config.globalProperties.$off = function (event, callback) {
this._eventBus.off(event, callback);
};
// 创建一个内部的事件总线
eventBus._eventBus = {
events: {},
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
},
emit(event, ...args) {
if (this.events[event]) {
this.events[event].forEach(callback => {
callback(...args);
});
}
},
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(cb => cb !== callback);
}
}
};
export default eventBus;
子组件
// src/eventBus.js
import { createApp } from 'vue';
const eventBus = createApp({});
// 添加自定义事件方法
eventBus.config.globalProperties.$emit = function (event, ...args) {
this._eventBus.emit(event, ...args);
};
eventBus.config.globalProperties.$on = function (event, callback) {
this._eventBus.on(event, callback);
};
eventBus.config.globalProperties.$off = function (event, callback) {
this._eventBus.off(event, callback);
};
// 创建一个内部的事件总线
eventBus._eventBus = {
events: {},
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
},
emit(event, ...args) {
if (this.events[event]) {
this.events[event].forEach(callback => {
callback(...args);
});
}
},
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(cb => cb !== callback);
}
}
};
export default eventBus;
父组件:
<template>
<ChildComponent />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
import eventBus from '../eventBus';
export default {
components: {
ChildComponent
},
created() {
// 监听事件
eventBus.$on('custom-event', this.handleCustomEvent);
},
beforeUnmount() {
// 组件销毁时移除事件监听
eventBus.$off('custom-event', this.handleCustomEvent);
},
methods: {
handleCustomEvent(message) {
console.log('Event received:', message);
// 在这里处理逻辑
}
}
}
</script>
使用类方法封装一个事件总线
// src/utils/EventBus.js
class EventBus {
constructor() {
this.events = {};
}
/**
* 监听事件
* @param {string} event - 事件名称
* @param {Function} callback - 回调函数
*/
$on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
/**
* 触发事件
* @param {string} event - 事件名称
* @param {...any} args - 传递给回调函数的参数
*/
$emit(event, ...args) {
if (this.events[event]) {
this.events[event].forEach(callback => {
callback(...args);
});
}
}
/**
* 移除事件监听
* @param {string} event - 事件名称
* @param {Function} callback - 回调函数
*/
$off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(cb => cb !== callback);
}
}
/**
* 一次性监听事件
* @param {string} event - 事件名称
* @param {Function} callback - 回调函数
*/
$once(event, callback) {
const onceCallback = (...args) => {
callback(...args);
this.$off(event, onceCallback);
};
this.$on(event, onceCallback);
}
}
// 创建一个 EventBus 实例
const eventBus = new EventBus();
export default eventBus;
子组件
<template>
<button @click="handleClick">点击我</button>
</template>
<script>
import eventBus from '../utils/EventBus';
export default {
methods: {
handleClick() {
// 触发事件
eventBus.$emit('custom-event', 'Hello from Child');
}
}
}
</script>
父组件
<template>
<ChildComponent />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
import eventBus from '../utils/EventBus';
export default {
components: {
ChildComponent
},
created() {
// 监听事件
eventBus.$on('custom-event', this.handleCustomEvent);
},
beforeUnmount() {
// 组件销毁时移除事件监听
eventBus.$off('custom-event', this.handleCustomEvent);
},
methods: {
handleCustomEvent(message) {
console.log('Event received:', message);
// 在这里处理逻辑
}
}
}
</script>