Vue3如何优雅的跨组件通信🚀🚀🚀
导读:开发中经常会遇到跨组件通信的场景。props 逐层传递的方法实在是太不优雅了,所以今天总结下可以更加简单的跨组件通信的一些方法。依赖注入<!-- App.vue --> <script setup lang="ts">...
开发中经常会遇到跨组件通信的场景。props 逐层传递的方法实在是太不优雅了,所以今天总结下可以更加简单的跨组件通信的一些方法。

依赖注入

!-- App.vue -->
script setup lang="ts">
import {
ref, provide }
from "vue";
import Child from "./components/Child.vue";
const count = ref(0)
const updateCount = () =>
count.value ++
provide("count", {
count, updateCount}
)
/script>
template>
h4>
公众号:萌萌哒草头将军/h4>
div>
{
{
count }
}
/div>
button @click="updateCount">
change/button>
Child />
/template>
!-- Child.vue -->
template>
Other />
/template>
script setup lang='ts'>
import Other from "./other.vue"
/script>
!-- other.vue -->
template>
div>
{
{
count }
}
/div>
button @click="updateCount">
other change/button>
/template>
script setup lang='ts'>
import {
inject }
from "vue"
const {
count, updateCount}
= inject("count")
/script>

在 setup 组件中,使用 inject 跨组件通信是最佳的方案。所以该模式下,是没有提供event bus 事件总线。
但是在 option api 模式下,还需要额外的注册,显的有点麻烦。
script lang='ts'>
export default {
emits: ["some-name"]
}
/script>
属性透传
!-- App.vue -->
script setup lang="ts">
import {
ref, provide }
from "vue";
import Attr from "./components/Attr.vue";
const count = ref(0)
const updateCount = () =>
count.value ++
provide("count", {
count, updateCount}
)
/script>
template>
h4>
公众号:萌萌哒草头将军/h4>
div>
{
{
count }
}
/div>
button @click="updateCount">
change/button>
Attr :count="count" :updateCount="updateCount" />
/template>
!-- Attr.vue -->
template>
div>
attr component/div>
Child v-bind="$attrs" />
/template>
script setup lang='ts'>
import Child from './Child.vue';
/script>

属性透传这种方式类似于react中手动透传属性。感觉有点暴力,但是又特别方便快捷。
function App (props) {
return Other {
...props}
/>
}
Vue中默认透传的属性有 style、class、key。如果子组件也存在class、style,则会自动合并class、style。
如果你的子组件是根组件时,可以省略 v-bind="$attrs"。
template>
Child />
/template>
状态库
状态管理库我们以Pinia为例。
!-- App.vue -->
script setup lang="ts">
import Other from "./components/Other.vue";
import {
useCounterStore }
from "./store/index"
const state = useCounterStore()
/script>
template>
h4>
公众号:萌萌哒草头将军/h4>
div>
{
{
count }
}
/div>
button @click="updateCount">
change/button>
Other />
/template>
import {
defineStore }
from "pinia"
import {
ref }
from "vue"
export const useCounterStore = defineStore('counter', () =>
{
const count = ref(0)
function updateCount() {
count.value++
}
return {
count, updateCount }
}
)
!-- Other.vue -->
template>
div>
pinia store/div>
div>
{
{
state.count }
}
/div>
button @click="state.updateCount">
other change/button>
/template>
script setup lang='ts'>
import {
useCounterStore }
from '../store';
const state = useCounterStore()
/script>

状态管理库最大的缺点是,没法使用结构语法。因为这会导致失去响应式的能力。
事件总线
事件总线(event bus)比较特殊,因为在组合式API里不支持该方式,所以下面的例子适合 Option API 组件。
!-- App.vue -->
script setup lang="ts">
import {
ref }
from "vue";
import Other from "./components/Other.vue";
const count = ref(0)
const updateCount = () =>
count.value ++
/script>
template>
h4>
公众号:萌萌哒草头将军/h4>
div>
{
{
count }
}
/div>
button @click="updateCount">
change/button>
Other @updateCount="updateCount()" />
/template>
!-- Other.vue -->
template>
div>
eventBus store/div>
button @click="$emit('updateCount')">
other change/button>
/template>
script lang='ts'>
export default {
emits: ["updateCount"]
}
/script>
事件总线更适合传递事件。
自定义事件
但是有时候,你可能非常想使用事件总线的方式在 setup 组件中传递事件,这时候我们可以使用自定义的事件的方式实现这种功能。
下面是实现。
class EventBus {
constructor() {
this.events = {
}
;
}
// 订阅事件
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
}
// 发布事件
emit(eventName, eventData) {
const eventCallbacks = this.events[eventName];
if (eventCallbacks) {
eventCallbacks.forEach(callback =>
{
callback(eventData);
}
);
}
}
// 取消订阅事件
off(eventName, callback) {
const eventCallbacks = this.events[eventName];
if (eventCallbacks) {
this.events[eventName] = eventCallbacks.filter(cb =>
cb !== callback);
}
}
}
export const eventBus = new EventBus()
!-- App.vue -->
script setup lang="ts">
import {
ref }
from "vue";
import Other from "./components/Other.vue";
import {
eventBus }
from "./store/eventBus";
const count = ref(0)
const updateCount = () =>
count.value ++
eventBus.on("updateCount", updateCount)
/script>
template>
h4>
公众号:萌萌哒草头将军/h4>
div>
{
{
count }
}
/div>
button @click="updateCount">
change/button>
Other @updateCount="updateCount()" />
/template>
!-- Other.vue -->
template>
div>
eventBus/div>
button @click="eventBus.emit('updateCount', null)">
other change/button>
/template>
script setup lang='ts'>
import {
eventBus }
from "../store/eventBus";
/script>

当然,我们这里不止可以使用 event bus,发布订阅模式也很适合。可以参考我以前的设计模式的文章实现这个功能。
总结
每种方式都有自己的优点和缺点,根据使用场景选择最合适的才能算是最优的方案。
今天的分享就这些了,十分感谢您的阅读,希望可以帮助到您。
声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!
若转载请注明出处: Vue3如何优雅的跨组件通信🚀🚀🚀
本文地址: https://pptw.com/jishu/572498.html