其他文章:
使用vite从头搭建一个vue3项目(一)创建vue3项目
使用vite从头搭建一个vue3项目(二)创建目录文件夹以及添加vue-router
使用vite从头搭建一个vue3项目(三)vite.config.js配置
使用vite从头搭建一个vue3项目(四)使用axios封装request.js文件,并使用proxy解决跨域问题
一、vue2中非父子组件传值方式
在vue2中,非父子组件(兄弟组件)之间传值经常使用 EventBus,被称作事件总线,其实质就是事件的订阅/发布功能。
通常是在 src
目录中单独声明一个文件 EventBus.vue
,然后返回一个 vue 实例,因为vue有自己的 API: $on
、$off
、$emit
,可以实现事件的订阅、发布功能。
// src/EventBus.vue
<script>
import Vue from 'vue';
export default new Vue();
</script>
使用 EventBus :
在 home 组件中监听事件。
// home/index.vue
<script>
import EventBus from '@/EventBus.vue'
export default {
data(){
return {
message: "",
date: "",
}
},
mounted(){
// 监听 getMessage 事件,获取数据
EventBus.$on('getMessage', getMessageData)
},
destroyed(){
// 取消监听 getMessage 事件
EventBus.$off('getMessage', getMessageData)
},
methods:{
getMessageData(data){
this.message = data.message;
this.date = data.date;
}
}
}
</script>
在 about 组件中触发事件。
// about/index.vue
<template>
<el-button @click="handleClick">点击我</el-button>
</template>
<script>
import EventBus from '@/EventBus.vue'
export default {
methods: {
handleClick(){
// 触发 getMessage 事件,传递数据
EventBus.$emit('getMessage', { message:'我的心好冷,我的心好痛', date:'2024-04-18' })
}
}
}
</script>
注意,因为 EventBus 为全局唯一,所以事件命名时要注意别重复!
二、vue3中非父子组件传值方式
因为 vue3 中移除了 $on
和 $off
实例方法,所以不再支持 EventBus 这种方式,推荐使用第三方插件 mitt
来实现事件的发布、订阅功能。
1、安装 mitt
npm install mitt
2、定义 emitter
在 src/utils
目录下创建 emitter.js 文件,emitter 的使用方式与 vue2 中 EventBus 的使用方式相同。
import mitt from 'mitt'
const emitter = mitt()
export default emitter
3、 emitter 的 API
- emitter.on() 监听事件
- emitter.off() 取消监听事件
- emitter.emit() 触发事件
- emitter.all.clear() 清除所有事件
emitter.all 是一个 new Map() 实例 ,所有的监听事件都会添加到 all 里面,所以会有 clear 方法 。
emitter.all 在 mitt 源码中的定义:
// 调用 mitt() 时可以传入一个监听事件 Map 参数,如果没有,则重新 new Map() 。
export default function mitt (all){
all = all || new Map();
return {
all
}
}
mitt API 使用方式:
import emitter from '@/utils/emitter'
// 监听单个事件
emitter.on('foo', e => console.log('foo', e) )
// 监听所有事件
emitter.on('*', (type, e) => console.log(type, e) )
// 触发事件
emitter.emit('foo', { a: 'b' })
// 清除所有事件
emitter.all.clear()
// 监听自定义事件
function onFoo() {}
emitter.on('foo', onFoo) // listen
emitter.off('foo', onFoo) // unlisten
mitt 第三方包地址:https://www.npmjs.com/package/mitt
4、示例
在 home 组件中定义事件 handleChange,显示弹框提示信息,在 onMounted 生命周期中监听自定义事件。在 about 组件中触发事件 handleChange,并提示信息。
// home/index.vue
<script setup>
import emitter from "@/utils/emitter"
import { ElMessage } from "element-plus"
function handleChange(data) {
ElMessage.success(data.message)
}
onMounted(() => {
// 判断,如果不存在 homeChange 事件,则添加监听事件;否则不做任何处理
if (!emitter.all.get('homeChange')) {
emitter.on('homeChange', handleChange)
}
})
// 此处注释掉 onUnmounted,是因为 home 切换为 about 组件时会卸载而执行当前生命周期,导致 emitter 监听事件失效;
// about 组件永远也不会触发 homeChange 事件,因为根本就没有监听,所以要注释掉。
// 当然,正常离开页面时是需要取消监听的,具体问题,具体分析啊。
// onUnmounted(() => {
// emitter.off('homeChange', handleChange)
// })
</script>
// about/index.vue
<script setup>
import { getMessage } from '@/api/about'
import emitter from "@/utils/emitter"
const message = ref("")
onMounted(() => {
handleClick();
})
function handleClick() {
getMessage().then(res => {
const { content } = res;
message.value = content;
// 触发 homeChange 事件并传值
emitter.emit('homeChange', { message: content })
})
}
</script>
效果: