在父子组件传递数据和方法时,会使用 props 和 emits ,当有一些多层级嵌套的组件,某个深层的子组件需要一个较远的祖先组件中的部分数据,我们还可以使用依赖注入(provide/inject)的方式来实现,但当深层子组件需要触发事件来修改祖先组件的数据时,逐级透传就会变的非常麻烦, 使用 Event-bus 进行组件通信帮我们解决了这一问题:
Vue3.x 不再提供 Vue2.x 里的 $on 和 $emit这两个实例方法,Vue3.x 中更推荐使用 mitt 这个库来实现
在 Nuxt3 中使用 mitt
1,以 plugins 的方式使用mitt
假设你已经了解 Nuxt 插件的工作方式 更多请查阅: nuxt.com/docs/guide/…
安装 mitt
npm install --save mitt
更多请查阅 mitt 文档
在根目录下创建plugins/event-bus.ts
// plugins/event-bus.ts
import mitt from 'mitt'
// 为 mitt 方法里的’modify-user‘事件标注类型
interface ModifyUser {
id: number
name: string
}
// 为 mitt 方法标注类型
type ApplicationEvents = {
'delete-user': number
'modify-user': ModifyUser
}
export default defineNuxtPlugin(() => {
const emitter = mitt<ApplicationEvents>()
return {
provide: {
emits: emitter.emit, // 触发事件方法 $emits
on: emitter.on // 监听事件方法 $on
}
}
})
在组件中使用
父组件:
// App.vue
<script setup lang="ts">
// 监听事件
const { $on } = useNuxtApp()
$on('delete-user', (id) => {
userList.value.forEach((item, index) => {
if (item.id === id) {
userList.value.splice(index, 1)
}
})
})
$on('modify-user', (userInfo) => {
const { id, name } = userInfo
userList.value.forEach((item) => {
if (item.id === id) {
item.name = name
}
})
})
</script>
后代组件:
// GrandChild.vue
<script setup lang="ts">
const { $emits } = useNuxtApp()
// 触发事件
const deleteUser = (id) => {
$emits('delete-user', id)
}
const modifyUser = (id,name) => {
customData.value.title = (e.target as HTMLInputElement).value
$emits('modify-title', {
id: id,
name: userName
})
}
</script>
2,以 composables 的方式使用 mitt
在根目录下创建 composables/useEventBus.ts
// composables/useEventBus.ts
import mitt from 'mitt'
// 为 mitt 方法里的’modify-user‘事件标注类型
interface ModifyUser {
id: number
name: string
}
// 为 mitt 方法标注类型
type ApplicationEvents = {
'delete-user': number
'modify-user': ModifyUser
}
const emitter = mitt<ApplicationEvents>()
export const useEmit = emitter.emit, // 触发事件方法 $emits
export const useOn = emitter.on // 监听事件方法 $on
}
}
})
在组件中使用
得益于Nuxt的自动导入功能,我们可以直接在组件中使用:
// App.vue
// 监听事件
useOn('delete-user',(id)=>{
console.log('delete user by id')
})
// GrandChild.vue
// 触发事件
useEmit('delete-user',id)