Vue中组件通信方式有哪些?

简介: 本文介绍了 Vue 中几种常见的组件间通信方式,包括 Props / $emit、provide / inject、ref / refs、eventBus、Vuex、$parent / $children、$attrs / $listeners 以及通过 vue-router 传参。每种方式都有其适用场景和注意事项,帮助开发者根据具体需求选择合适的通信方式。

本文首发微信公众号:前端徐徐。

Props / $emit

Props用于父子组件通信:当一个组件需要向它的子组件传递数据时;$emit用于子父组件通信:当子组件需要向父组件发送消息或触发事件时。

父组件:

<template>
  <ChildComponent :message="parentMessage" @customEvent="handleCustomEvent" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentMessage: 'Hello from parent!'
    };
  },
  methods: {
    handleCustomEvent(payload) {
      console.log('Received from child:', payload);
    }
  }
};
</script>

子组件:

<template>
  <div>
    <div>
      {{ message }}
    </div>
    <button @click="sendDataToParent">Send Data</button>
  </div>
</template>
<script>
export default {
  props: ['message'],
  methods: {
    sendDataToParent() {
      this.$emit('customEvent', 'Data sent from child');
    }
  }
};
</script>

Props 和 $emit 是 Vue 中常用的父子组件通信方式,分别用于从父组件向子组件传递数据和从子组件向父组件触发事件。这种方式是 Vue 中最常见和推荐的通信方式之一。

provide/inject

当你需要在组件树中的祖先组件向子孙组件传递数据时,可以使用 provideinject。这种方式不同于传统的父子组件通信,它允许你在一个祖先组件中提供数据,然后在后代组件中注入并使用这些数据。

使用场景:

  • 当你有一个组件层次结构,需要在多个后代组件中共享相同的数据,例如主题、语言设置等。
  • 当你想要在深层次的子组件中访问一些全局数据,而不必通过每个中间组件进行传递。

祖先组件:

<template>
  <div>
    <ChildComponent />
  </div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
  components: {
    ChildComponent
  },
  provide() {
    return {
      sharedMessage: 'This message is shared!'
    };
  }
};
</script>

后代组件:

<template>
  <div>{{ sharedMessage }}</div>
</template>
<script>
export default {
  inject: ['sharedMessage']
};
</script>

⚠️注意事项:

  • inject 会创建一个响应式的绑定,但它的更新是从父组件到子孙组件的单向流动,这意味着如果你在子孙组件中修改了 inject 的值,不会影响到祖先组件的数据。
  • 虽然 provideinject 提供了一种组件之间共享数据的方式,但也要谨慎使用,避免滥用,因为它可能导致组件之间的耦合增加

ref / refs

refrefs 是 Vue 中用于获取对组件或 DOM 元素的引用的机制。通过使用 ref 属性,你可以在父组件中获取对子组件的引用,然后通过 $refs 对象访问这些引用。

使用场景:

  • 当你需要在父组件中调用子组件的方法或访问子组件的属性。
  • 当你需要直接操作子组件关联的 DOM 元素。

父组件:

<template>
  <div>
    <ChildComponent ref="childComponentRef" />
    <button @click="callChildMethod">Call Child Method</button>
  </div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
  components: {
    ChildComponent
  },
  methods: {
    callChildMethod() {
      this.$refs.childComponentRef.childMethod();
    }
  }
};
</script>

子组件:

<template>
  <div>Child Component</div>
</template>
<script>
export default {
  methods: {
    childMethod() {
      console.log('Child method called');
    }
  }
};
</script>

⚠️注意事项:

  • 使用 ref$refs 需要谨慎,因为它可能导致你绕过了 Vue 的响应式数据流,增加了组件之间的耦合。

eventBus

EventBus 是一种 Vue 中用于实现组件间通信的简单的事件总线模式。它是通过创建一个空的 Vue 实例,作为中央事件管理器,用于在组件之间传递事件和数据。尽管它是一种简单的通信方式,但在一些简单的应用场景中是有效的。

使用场景:

  • 当多个组件之间需要进行非父子关系的通信时,或者当组件之间的层级结构较复杂时。
  • 当你有多个组件,但只有几个之间需要共享数据或响应事件。

创建 EventBus 实例:

// EventBus.js
import Vue from 'vue';
export const EventBus = new Vue();

组件中使用

<template>
  <div>
    <button @click="sendMessage">Send Message</button>
  </div>
</template>
<script>
import { EventBus } from './EventBus.js';
export default {
  methods: {
    sendMessage() {
      EventBus.$emit('messageSent', 'Hello from EventBus!');
    }
  }
};
</script>

在另一个组件中监听并接收事件:

<template>
  <div>
    <p>{{ receivedMessage }}</p>
  </div>
</template>
<script>
import { EventBus } from './EventBus.js';
export default {
  data() {
    return {
      receivedMessage: ''
    };
  },
  created() {
    EventBus.$on('messageSent', message => {
      this.receivedMessage = message;
    });
  }
};
</script>

⚠️注意事项

  • EventBus 是一种全局事件总线,过度使用可能导致代码难以维护,应谨慎使用。

Vuex

Vuex 是 Vue.js 的官方状态管理库,用于管理应用程序的状态(数据)。它提供了一种集中式的状态管理模式,使得多个组件可以共享和操作同一个状态,从而实现更复杂的数据流控制和组件通信。

使用场景:

  • 当多个组件需要访问相同的数据或状态时。
  • 当你的应用程序的状态逻辑变得复杂,需要更好地组织和管理数据流。
  • 当你需要在组件之间进行复杂的异步操作和数据操作时。
  • 当你想要实现中央化的数据管理,而不是在组件之间传递数据。

设置 Vuex Store

// store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
  state: {
    message: 'Hello from Vuex!'
  },
  mutations: {
    updateMessage(state, newMessage) {
      state.message = newMessage;
    }
  },
  getters: {
    getMessage: state => state.message
  }
});

在组件中使用 Vuex

<template>
  <div>
    <p>Message from Vuex: {{ message }}</p>
  </div>
</template>
<script>
import { mapState } from 'vuex';
export default {
  computed: {
    ...mapState(['message'])
  }
};
</script>

在其他组件中使用 Vuex

<template>
  <div>
    <p>Message from Vuex in another component: {{ message }}</p>
    <button @click="updateMessage">Update Message</button>
  </div>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
export default {
  computed: {
    ...mapState(['message'])
  },
  methods: {
    ...mapMutations(['updateMessage'])
  }
};
</script>

$parent/$children

$parent $children 是 Vue 实例提供的两个属性,用于在组件内部访问其父组件和子组件。

使用场景:

  • 一个组件中访问其直接父组件或子组件的属性或方法时

父组件:

<template>
  <div>
    <ChildComponent />
    {{ parentMessage }}
    <button @click="getChild">getChild</button>
  </div>
  
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentMessage: 'Hello from parent!'
    };
  },
  methods : {
    getChild(){
      console.log(this.$children[0])
    }
  }
};
</script>

子组件:

<template>
  <div>
    <button @click="setParent">setParent</button>
  </div>
</template>
<script>
export default {
  name: 'ChildComponent',
  methods: {
    setParent() {
      //  通过$parent我们可以获取父组件实例,并设置值
      this.$parent.parentMessage = 'Hello from ChildComponent!'
    }
  }
};
</script>

⚠️注意事项:

  • 使用 $parent 和 $children 会造成高度耦合,不推荐过度使用
  • $parent 和 $children 无法跨级访问,只能访问直接的父子关系
  • 在Vue3中无法访问$children,需要使用 refs

$attrs/$listeners

$attrs$listeners 是 Vue 中用于处理组件属性和事件的特殊属性。它们主要用于在具有嵌套关系的组件中传递属性和事件。

使用场景:

  • 通常在高阶组件(Higher Order Component,HOC)或其他需要将属性和事件传递到子组件的场景中使用。

父组件:

<template>
  <ChildComponent v-bind="$attrs" v-on="$listeners"/>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
  components: {
    ChildComponent
  }
};
</script>

子组件:

<template>
  <div>
    {{ propFromParent }}
    <button @click="$emit('custom-event')">Trigger Custom Event</button>
  </div>
</template>
<script>
export default {
  props: {
    propFromParent: String
  }
};
</script>

Local Storage/Session Storage

LoLocalStorage 和 SessionStorage 可以用来在 Vue 组件之间共享数据,原理是不同组件实例都可以访问同一个本地存储。

使用LocalStorage

在组件A中:

// 写入数据
localStorage.setItem('name', 'John')
// 读取数据
const name = localStorage.getItem('name')

在组件B中:

// 读取组件A写入的数据
const name = localStorage.getItem('name')

使用SessionStorage

同理,使用sessionStorage:

组件A:

sessionStorage.setItem('age', 20)

组件B:

const age = sessionStorage.getItem('age')

LocalStorage的数据会长期保存,SessionStorage的数据只存在于当前会话,刷新后清空。

⚠️注意事项:

  • 不能很方便地做数据监听,需要手动watch
  • 存储容量较小(仅5MB左右)
  • LocalStorage/SessionStorage只适合用于非核心的组件间数据共享,不适合复杂应用状态管理

vue-router

严格来说,vue-router通过路由传参实现的不完全是组件之间的通信,而是通过路由参数在不同路由(组件)之间传递数据。但确实可以把它看作一个间接的组件通信方式。

组件A

// 传递userId参数
this.$router.push({
  name: 'user',
  params: {
    userId: 1234
  }  
})

在组件B中(user组件)

// 接收userId参数
const userId = this.$route.params.userId

通过这种方式,可以在A组件和B组件之间传递参数,实现了某种形式的组件间通信。

⚠️注意事项:

  • 组件之间存在依赖关系,不够纯粹。


相关文章
|
1天前
|
编解码 Java 程序员
写代码还有专业的编程显示器?
写代码已经十个年头了, 一直都是习惯直接用一台Mac电脑写代码 偶尔接一个显示器, 但是可能因为公司配的显示器不怎么样, 还要接转接头 搞得桌面杂乱无章,分辨率也低,感觉屏幕还是Mac自带的看着舒服
|
3天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1540 5
|
1月前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
7天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
577 22
|
3天前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
201 3
|
10天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
10天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
571 5
|
23天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
6天前
|
XML 安全 Java
【Maven】依赖管理,Maven仓库,Maven核心功能
【Maven】依赖管理,Maven仓库,Maven核心功能
233 3
|
9天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
327 2