Vue3优雅的实现跨组件通信的常用方法总结
前言
开发中经常会遇到跨组件通信的场景。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>
在 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,发布订阅模式也很适合。可以参考我以前的设计模式的文章实现这个功能。
总结
每种方式都有自己的优点和缺点,根据使用场景选择最合适的才能算是最优的方案。
以上就是Vue3优雅的跨组件通信的常用方法总结的详细内容,更多关于Vue3跨组件通信的资料请关注脚本之家其它相关文章!
相关文章
Vue通过getAction的finally来最大程度避免影响主数据呈现问题
这篇文章主要介绍了Vue通过getAction的finally来最大程度避免影响主数据呈现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2020-04-04
最新评论