Vue 3 第十一章:组件二(组件通信)

1. 组件的通信

1.1. 父子组件之间的通信

1.1.1 父组件向子组件传值

方式一:父组件给子组件传值时,通过v-on绑定属性实现

// parent.vue
<template>
  <div>
    父子组件传值
    <children :msg="msg" :foo="foo"/>
  </div>
</template>

<script setup lang="ts">
import {
      
       ref } from 'vue';
import children from './components/children.vue';

let msg = ref('hello word');
let foo = ref(10);
</script>

<style scoped>

</style>

子组件通过defineProps来接收接收父组件传递的值。

  • 使用字符串的形式接收父组件传递的值
// children.vue
<template>
  <div class="wrapper">
    这是子组件<br/>
    父传子:{
   
   { props.msg }} {
   
   { props.foo }}
  </div>
</template>

<script setup lang="ts">
let props = defineProps(['msg', 'foo'])
</script>

<style scoped>

</style>
  • 使用对象的形式接收父组件传递的值
// children.vue
<template>
  <div class="wrapper">
    这是子组件<br/>
    父传子:{
   
   { props.msg }} {
   
   { props.foo }}
  </div>
</template>

<script setup lang="ts">
let props = defineProps({
      
      
  msg: String,
  foo: Number
})
</script>

<style scoped>

</style>
  • 使用对象的形式接收父组件传递的值(含默认值及必填参数设置)
// children.vue
<template>
  <div class="wrapper">
    这是子组件<br/>
    父传子:{
   
   { props.msg }} {
   
   { props.foo }}
  </div>
</template>

<script setup lang="ts">
let props = defineProps({
      
      
  msg: {
      
      
    type: String,
    default: '',
    required: true // 设置后参数必传
  },
  foo: {
      
      
    type: Number,
    default: 0
  }
})
</script>

<style scoped>

</style>
  • 结合 TypeScript 使用
// children.vue
<template>
  <div class="wrapper">
    这是子组件<br/>
    父传子:{
   
   { props.msg }} {
   
   { props.foo }}
  </div>
</template>

<script setup lang="ts">
let props = defineProps<{
      
      
  msg?: string;
  foo: number
}>()
</script>

<style scoped>

</style>

方式二:父组件通过插槽(slot)向子组件传递参数

  • 子组件中通过slot标签传递参数
  • 父组件中通过template插入内容,通过v-slot可以接收插槽传递的数据
<!-- Parent.vue -->
<template>
  <Child>
    <template #default="{ message }">
      {
   
   { message }}
    </template>
  </Child>
</template>

<script>
import Child from './Child.vue'
</script>

<!-- Child.vue -->
<template>
  <div>
    <slot :message="message"></slot>
  </div>
</template>

<script setup lang="ts">
import {
      
       ref } from 'vue'
const message = ref('Hello, world!')
</script>

需要注意的是,插槽只能用于传递静态内容,如果需要传递动态内容,则需要使用props或者provide/inject来实现。此外,插槽还可以定义多个,并且可以通过name属性来区分不同的插槽。

方式三:v-model,子组件可直接修改父组件传递过来的值

在Vue3中,可以使用v-model指令来实现子组件直接修改父组件传递过来的值。具体来说,可以在父组件中使用v-model指令将一个变量与子组件的一个prop绑定起来,然后在子组件中使用emit方法触发一个名为update:加上prop名字的事件,并传递一个新的值作为参数。例如:

<!-- VmodelParent.vue -->
<template>
  <div>
    v-model传参:父组件
    <VmodelChild v-model:isShow="isShow" />
  </div>
</template>

<script setup lang="ts">
import {
      
       ref } from 'vue';
import VmodelChild from './components/VmodelChild.vue';

const isShow = ref(false)

</script>

<style scoped>

</style>



<!-- VmodelChild.vue -->
<template>
  <div>
    v-model传参:子组件
    <button @click="handleClick">点击修改参数</button>
    <br />
    {
   
   { props.isShow }}
  </div>
</template>

<script setup lang="ts">
import {
      
       defineProps, defineEmits } from 'vue';

const props = defineProps({
      
      
  isShow: {
      
      
    type: Boolean,
    default: false
  }
})
const emit = defineEmits(["update:isShow"])
const handleClick = () => {
      
      
  emit("update:isShow", !props.isShow)
}

</script>

<style scoped>

</style>

1.1.2. 子组件向父组件传值

子组件向父组件传值,通过defineEmits实现

<template>
  <div class="wrapper">
    这是子组件<br/>
    <button @click="emitToParent">click</button>
  </div>
</template>

<script setup lang="ts">
let emit = defineEmits(['event-to-parent'])
let emitToParent = () => {
      
      
  emit('event-to-parent', '子组件传递给父组件的值')
}

</script>

<style scoped>

</style>

1.2. 兄弟组件之间的通信

Vue 3 中移除了 eventBus,但可以借助第三方工具来完成。Vue 官方推荐使用mitt tiny-emitter

例子:以mitt为例

1.2.1. 安装

yarn add mitt -S

1.2.2. 注册

  • eventBus.ts
// eventBus.ts
import mitt from 'mitt'

const mitter = mitt();

export default mitter

1.2.3. 使用

  • EventBus.vue
// EventBus.vue
<template>
  <div>
    Event Bus实现兄弟组件传参
    <EventBusA />
    <EventBusB />
  </div>
</template>

<script setup lang="ts">
import EventBusA from './components/EventBusA.vue';
import EventBusB from './components/EventBusB.vue';
</script>

<style scoped>

</style>
  • EventBusA.vue
// EventBusA.vue
<template>
  <div class="wrapper">
    兄弟组件A
    <button type="button" @click="handleClick">点击传参</button>
  </div>
</template>

<script setup lang="ts">
import {
      
       ref } from 'vue';
import mitter from '@/utils/eventBus'

const msg = ref('Hello, world!')

const handleClick = () => {
      
      
  mitter.emit('msg', msg.value)
}

</script>

<style scoped>

</style>
  • EventBusB.vue
// EventBusB.vue
<template>
  <div class="wrapper">
    兄弟组件B
    {
   
   { res }}
  </div>
</template>

<script setup lang="ts">
import mitter from '@/utils/eventBus'
import {
      
       ref } from 'vue'

const res = ref()

mitter.on('msg', (data) => {
      
      
  res.value = data
})
</script>

<style scoped>

</style>

1.3. 跨级组件之间的通信

provide/inject来实现跨级组件之间的通信

1.3.1 provide/inject

  • parent.vue
// parent.vue
<template>
  <div class="wrapper">
    兄弟组件传参,这是父组件
    <brotherA />
    <brotherB />
  </div>
</template>

<script setup lang="ts">
import brotherA from './components/brotherA.vue'
import brotherB from './components/brotherB.vue'
import {
      
       provide, ref } from 'vue';

let msg = ref('给孙组件传递的值');
provide('msg', msg)

</script>

<style scoped>

</style>
  • brotherA.vue
// brotherA.vue
<template>
  <div class="wrapper">
    子组件A
    <grandson />
  </div>
</template>

<script setup lang="ts">
import grandson from "./grandson.vue";
import {
      
       ref } from 'vue';


</script>

<style scoped>

</style>
  • brotherB.vue
// brotherB.vue
<template>
  <div class="wrapper">
    子组件B
    {
   
   { msg }}
  </div>
</template>

<script setup lang="ts">
import {
      
       inject } from 'vue'

let msg = inject('msg')
</script>

<style scoped>

</style>
  • grandson.vue
// grandson.vue
<template>
  <div class="wrapper">
    这是孙组件
    {
   
   { msg }}
  </div>
</template>

<script setup lang="ts">
import {
      
       inject } from 'vue'

let msg = inject('msg')
</script>

<style scoped>

</style>

1.4. 非父子组件之间的通信

1.4.1. Vuex/Pinia

Vuex 和 Pinia 是 Vue 3 中的状态管理工具,使用这两个工具可以轻松实现组件通信。由于这两个工具都比较强大,后面会写文章详细讲解。

总结

组件通信是 Vue 中非常重要的一个概念,它指的是组件之间传递数据和事件的过程。在 Vue 中,组件通信主要分为父子组件之间的通信和兄弟组件之间的通信两种情况。
在父子组件之间的通信中,父组件可以通过v-bind来向子组件传递数据,而子组件则可以通过defineProps来接收父组件传递的数据。同时,子组件也可以通过emit触发自定义事件来向父组件传递数据。
在兄弟组件之间的通信中,可以通过一个共同的父组件来实现数据的传递和事件的触发,也可以通过 Vuex 等状态管理工具来实现数据的共享。
总之,在组件通信的过程中,需要合理地选择合适的方法来实现数据和事件的传递,以实现组件之间的良好协作和高效交互。

猜你喜欢

转载自blog.csdn.net/to_the_Future/article/details/129542576