非父子组件通信

本文介绍了在 Vue.js 中实现非父子组件通信的两种常见方法:中间人模式和中央总线(Event Bus)。中间人模式通过引入一个中间组件来传递数据,而中央总线则利用新建的 Vue 实例作为全局事件总线,组件通过监听和触发事件来实现通信。示例代码详细展示了这两种通信方式的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

非父子组件通信有以下两种方式:中间人模式 && bus中央总线

<!-- child1 && child2都是组件,并且他们组件之间没有嵌套关系,这种情况下child1和child2需要进行通信,我们称之为非父子组件通信-->
<div id="box">
  <child1></child1>
  <child2></child2>
</div>

中间人模式

两个组件A,B没有办法通信。我们采用一个中间组件C,让A先和C通信,得到数据后,再由C传递给B

案例:

  1. film-item组件先通过子传父,将数据传到父组件
    this.$emit(“callback”,this.item.synopsis)
  2. 父组件接受数据,并传递给film-detail子组件
    handleCallBack(data){ this.detailInfo = data }
<div id="box">
   <button @click="handleAjax">ajax</button>
   <film-item v-for="item in datalist" :key="item.filmId" :item="item"  @callback="handleCallBack"></film-item>
   <film-detail :myinfo="detailInfo"></film-detail>
</div>
Vue.component("film-detail",{
    props:["myinfo"],/// this.myinfo myinof
    template:`
        <div class="filminfo">
            {{myinfo}}
        </div>
    `
})

Vue.component("film-item",{
    props:["item"],//接受属性, this.item
    template:`
        <div class="item">
            <img :src="item.poster"/>
            <div>{{item.name}}</div>
            <button @click="handleDetail">详情</button>   
        </div>
    `,
    methods:{
        handleDetail(){
            // console.log(this.item.synopsis)
            this.$emit("callback",this.item.synopsis)
        }
    }
})

new Vue({
   el:"#box",
    data:{
        datalist:[],
        detailInfo:""
    },
    methods:{
        handleAjax(){
            fetch("json/test.json").then(res=>res.json())
            .then(res=>{
                // console.log(res)
                this.datalist = res.data.films
            })
        },
        handleCallBack(data){
            // console.log("父组件触发",data)
            this.detailInfo = data
        }
    }
})

bus中央总线

一个组件负责监听bus.$on,一个组件负责触发bus.$emit
mounted生命周期中进行监听

<div id="box">
   <button @click="handleAjax">ajax</button>
   <film-item v-for="item in datalist" :key="item.filmId" :item="item"></film-item>
   <film-detail></film-detail>
</div>
var bus = new Vue() //中央事件总线
Vue.component("film-detail",{  
  template:`
      <div class="filminfo">
         {{info}}
      </div>
  `,
  data(){
      return {
          info:""
      }
  },
  // 8个生命周期 ---mounted
  mounted(){
      console.log("mounted","当前挂载到页面上就会执行")
      bus.$on("kerwin",(data)=>{
          // console.log("kerwin事件",data)
          this.info = data
      })
  }
})

Vue.component("film-item",{
  props:["item"],//接受属性, this.item
  template:`
      <div class="item">
          <img :src="item.poster"/>
          <div>{{item.name}}</div>
          <button @click="handleDetail">详情</button>   
      </div>
  `,
  methods:{
      handleDetail(){
          bus.$emit("kerwin", this.item.synopsis)
      }
  }
})
new Vue({
  el:"#box",
  data:{
      datalist:[],
  },
  methods:{
      handleAjax(){
          fetch("json/test.json").then(res=>res.json())
          .then(res=>{
              this.datalist = res.data.films
          })
      }
  }
})
<think>嗯,用户问的是Vue3中非父子组件通信的方法。我需要先回想一下Vue3的相关知识,尤其是组件通信的方式。Vue3中常用的通信方式除了props和emit之外,非父子组件之间的通信有哪些呢?首先想到的是全局事件总线,不过Vue3中移除了$on、$off这些方法,可能需要用mitt这样的第三方库来实现。然后是Provide/Inject,这应该是Vue3推荐的方式之一,适合祖先和后代组件之间的通信。还有Vuex或者Pinia状态管理库,用来集中管理状态,适用于多个组件共享数据的场景。另外,还有使用Reactive Objects,通过导出一个响应式对象,让不同组件引入同一个实例来实现数据共享。可能还有LocalStorage或者SessionStorage,不过这些属于浏览器存储,不是Vue特有的方法。 用户可能需要具体的实现例子,所以每种方法都应该给出简单的代码示例。比如mitt的使用步骤,如何安装、创建实例、在组件中触发和监听事件。Provide和Inject的用法,需要注意响应式数据需要使用ref或reactive,并通过provide传递。状态管理的话,可能需要简要介绍Pinia的基本用法,因为Vue3推荐使用Pinia代替Vuex。Reactive Objects的例子需要展示如何导出一个响应式对象,并在不同组件中引用。 还要考虑用户可能的疑问,比如各种方法的适用场景和优缺点。比如事件总线适合组件间松耦合的通信,但需要手动管理事件监听;Provide/Inject适合层级较深的组件,但可能会造成数据来源不明确的问题;状态管理适合大型应用,但需要引入额外库。需要提醒用户根据项目需求选择合适的方式。 需要检查是否有遗漏的方法,比如使用Vue3的app.config.globalProperties来挂载全局对象,但这种方式可能不如其他方法规范。或者使用Composition API中的自定义hook来共享状态,不过这可能和Reactive Objects的方法类似。 另外,用户的问题是关于非父子组件,所以兄弟组件、跨多级组件的情况都需要涵盖。确保每种方法的说明足够清晰,步骤明确,代码正确。可能需要比较不同方法之间的差异,帮助用户做出选择。 总结下来,回答的结构应该是分点列出各种方法,每种方法包含原理、适用场景、实现步骤和示例代码。同时最后给出选择建议,根据项目规模和需求推荐合适的方式。需要确保语言简洁明了,避免技术术语过于晦涩,让不同层次的开发者都能理解。</think>在 Vue3 中实现非父子组件通信主要有以下 5 种常用方案,每种方案都有不同的适用场景: 一、全局事件总线(Event Bus) ```javascript // 使用 mitt 库(需先安装) import mitt from 'mitt'; const emitter = mitt(); // 组件 A(发送事件) emitter.emit('custom-event', { data: 'Hello' }); // 组件 B(接收事件) emitter.on('custom-event', (payload) => { console.log(payload.data); // 输出 Hello }); // 组件卸载时记得移除监听 onUnmounted(() => { emitter.off('custom-event'); }); ``` 二、Provide/Inject(依赖注入) ```javascript // 祖先组件 import { provide, ref } from 'vue'; const sharedData = ref('初始值'); provide('globalData', sharedData); // 后代组件 import { inject } from 'vue'; const receivedData = inject('globalData'); ``` 三、状态管理(Pinia) ```javascript // store/counter.js import { defineStore } from 'pinia'; export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), actions: { increment() { this.count++; } } }); // 组件中使用 import { useCounterStore } from '@/stores/counter'; const store = useCounterStore(); console.log(store.count); // 访问状态 store.increment(); // 修改状态 ``` 四、响应式对象共享 ```javascript // sharedState.js import { reactive } from 'vue'; export const state = reactive({ message: '共享数据' }); // 组件 A import { state } from './sharedState'; state.message = '新消息'; // 组件 B import { state } from './sharedState'; console.log(state.message); // 输出 "新消息" ``` 五、浏览器存储 ```javascript // 组件 A localStorage.setItem('sharedKey', JSON.stringify({ data: 'value' })); // 组件 B const data = JSON.parse(localStorage.getItem('sharedKey')); ``` 方案选择建议: 1. 简单场景:事件总线(少量通信)或响应式对象 2. 层级嵌套:优先使用 Provide/Inject 3. 复杂应用:推荐使用 Pinia 状态管理 4. 页面级持久化:考虑 localStorage 注意事项: - 事件总线需注意及时清理事件监听 - Provide/Inject 要避免过度使用导致组件耦合 - Pinia 需要合理设计模块结构 - 响应式对象共享要注意单例模式实现 - 浏览器存储需处理序列化和存储限制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值