props / $emit
只能适合父子组件通信;不适用跨层组件通信
<!-- Parent.vue -->
<template>
<!-- custom-event -->
<ChildComponent :message="parentMessage" @custom-event="handleEvent" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
data() {
return {
parentMessage: '父级数据'
};
},
methods: {
handleEvent(data) { // handleEvent
console.log(data);
}
},
components: {
ChildComponent
}
};
</script>
<!-- ChildComponent.vue -->
<template>
<p @click="sendEvent">{{ message }}</p> <!-- sendEvent事件 -->
</template>
<script>
export default {
props: {
message: {
type: String,
required: true
}
},
methods: {
sendEvent() {
this.$emit('custom-event', '子组件数据'); // $emit
}
}
};
</script>
provice / inject
适合跨层级组件通信;它和mitt的区别是,inject
更适用于有嵌套关系的组件间通信
优点:避免了通过多层 props 传递数据的繁琐,使得组件间的数据流动更加清晰和灵活
缺点:增加了组件之间的耦合性;滥用会使项目难以维护
<!-- GrandParent.vue -->
<template>
<ParentComponent />
</template>
<script>
import ParentComponent from './ParentComponent.vue';
export default {
provide() { // provide
return {
message: 'Hello from GrandParent'
};
},
components: {
ParentComponent
}
};
</script>
<!-- ParentComponent.vue -->
<template>
<ChildComponent />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
<!-- ChildComponent.vue -->
<template>
<p>{{ message }}</p>
</template>
<script>
export default {
inject: ['message'] // inject
};
</script>
EventBus/mitt
通过发布订阅的方式实现跨组件的事件通信;适用于无直接关系的组件间通信;
使用 mitt 作为示例(因为 EventBus 是 Vue 2 中的一个非正式模式,而 mitt 是一个轻量级的替代方案)
// VUE3
// npm install mitt
// event-bus.js
import mitt from 'mitt';
export const EventBus = mitt();
// 组件A
<script>
import { EventBus } from './event-bus';
export default {
methods: {
sendDataToB() {
EventBus.emit('data-to-b', 'Hello from A!');
}
}
}
</script>
// 组件B
<script>
import { EventBus } from './event-bus';
export default {
mounted() {
EventBus.on('data-to-b', (data) => {
console.log(data); // 输出: Hello from A!
});
},
beforeDestroy() {
// 组件销毁前移除监听器
EventBus.off('data-to-b');
}
}
</script>
// VUE2
// main.js
import Vue from 'vue';
// 创建一个新的Vue实例作为事件总线
const bus = new Vue();
// 将事件总线挂载到Vue的原型链上,这样在任何组件中都可以通过this.$bus来访问
Vue.prototype.$bus = bus;
// ComponentA.vue
export default {
methods: {
sendMessage() {
// 使用$emit触发事件,事件名为"eventName",参数为"message"
this.$bus.$emit('eventName', 'message');
}
}
}
// ComponentB.vue
export default {
mounted() {
// 使用$on监听事件
this.$bus.$on('eventName', (message) => {
console.log(message); // 输出:message
});
},
beforeDestroy() {
// 一定要在组件销毁前移除事件监听,防止内存泄露
this.$bus.$off('eventName');
}
}
mitt
是事件发射器库,用于跨组件通信;inject
是 Vue.js 框架的选项,用于跨层级组件通信。