首页前端开发VUEVue3如何优雅的跨组件通信🚀🚀🚀

Vue3如何优雅的跨组件通信🚀🚀🚀

时间2023-12-07 22:26:03发布访客分类VUE浏览1113
导读:开发中经常会遇到跨组件通信的场景。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
深入理解HTML预加载技术:DNS预获取 浅学前端:Vue篇(二)

游客 回复需填写必要信息