“【VUE3系列】常见的5种Vue组件通信方法”

在 Vue.js 中,组件通信是开发过程中非常重要的一部分,它涉及到不同组件之间的数据传递和交互。本文将介绍如何实现父子组件之间的有效通信,包括 Props、双向绑定、ref、以及 provide/inject 这几种常见的组件通信方式。

1. 父子通信(Props)

在 Vue.js 中,父子组件通信的最基本方式是通过 Props。父组件可以向子组件传递数据或方法,子组件通过 props 接收这些数据,从而实现父子组件之间的通信。

父组件:

xml 复制代码
<!-- Parent.vue -->
<template>
  <div class="hd">
    <input type="text" name="" id="" v-model="msg">
    <button @click="add">添加 </button>
  </div>
  <Child :list="list" />
</template>

<script setup>
import { ref } from 'vue'
import Child from './components/Child.vue'
const list = ref(['html', 'css'])

const msg = ref('')

const add = () => {
  list.value.push(msg.value)

}
</script>

子组件:

xml 复制代码
<!-- Child.vue -->
<template>
    <div class="bd">
        <ul>
            <li v-for="item in list">{{ item }}</li>
        </ul>
    </div>
</template>

<script setup>

import { defineProps } from 'vue';
defineProps({
    list: {
        type: Array,
        default: () => []
    }
})
</script>

父子通信(Props)的优点和缺点如下:

优点:

  1. 简单易懂: Props 是 Vue.js 中最基本的组件通信方式之一,使用简单直观,易于理解和上手。

  2. 单向数据流: 父组件通过 Props 向子组件传递数据,这种单向数据流使得数据变化的来源清晰明了,便于追踪和调试。

  3. 组件解耦: 使用 Props 可以让组件之间保持相对独立,提高了组件的可复用性和可维护性。

缺点:

  1. 层级限制: Props 是父子组件之间的通信方式,当组件层级较深时,需要逐层传递 Props,增加了组件间的耦合性。

  2. 大规模应用复杂性: 在大型应用中,如果组件关系错综复杂,过多的 Props 传递会导致代码不够清晰,维护起来较为困难。

  3. 数据冗余: 有时为了满足一个子组件的特定需求,需要在父组件中传递较多的数据,可能会导致数据冗余或不必要的传递。

2. 子父通信($emit)

子组件可以使用 $emit 方法发布一个事件,父组件可以通过监听这个事件来订阅,从而实现子父组件之间的通信。

子组件:

xml 复制代码
<!-- Child.vue -->
<template>
    <div class="hd">
        <input type="text" name="" id="" v-model="msg">
        <button @click="add">添加</button>
    </div>

</template>

<script setup>
import { ref } from 'vue';

const msg = ref('')
const emits = defineEmits(['add']) //创建一个add事件

const add = () => {
    emits('add', msg.value);
    console.log(msg.value);
    msg.value = '';
}

</script>

父组件:

xml 复制代码
<!-- Parent.vue -->
<template>
    <Child @add="handle" />

    <div class="bd">
        <ul>
            <li v-for="item in list">{{ item }}</li>
        </ul>
    </div>

</template>

<script setup>
import { ref } from 'vue';
import Child from './components/Child.vue'

const list = ref(['html', 'css'])

const handle = (e) => {
    list.value.push(e)
}
</script>

子父通信($emit)的优点和缺点如下:

优点:

  1. 灵活性: 使用 $emit 实现子父通信可以非常灵活地传递数据和消息,子组件可以向父组件传递任意类型的数据。

  2. 解耦合: 子组件通过 $emit 触发事件,父组件监听事件,实现了组件之间的解耦合,提高了组件的独立性和复用性。

  3. 响应式: 通过 $emit 传递的数据在父组件中是响应式的,可以实时更新视图,提高了用户体验。

缺点:

  1. 事件命名冲突: 如果项目较大或组件较多,可能会出现事件命名冲突的情况,需要谨慎管理事件名称。

  2. 跨级通信复杂性: 当组件层级较深时,子组件向父组件传递数据可能需要经过多层中间组件,增加了通信的复杂性。

  3. 不适用于兄弟组件通信: $emit 主要用于子组件向父组件传递数据,对于兄弟组件之间的通信并不直接适用,需要借助其他方式实现。

3. 子父通信(双向绑定)

子组件可以通过 $emit 方法将修改后的数据发送给父组件,父组件可以通过 v-model 在子组件上实现双向绑定,实现父子组件之间数据的双向同步。

父组件:

xml 复制代码
<!-- Parent.vue -->
<template>
    <Child v-model:list="list" />

    <div class="bd">
        <ul>
            <li v-for="item in list">{{ item }}</li>
        </ul>
    </div>

</template>

<script setup>
import { ref } from 'vue';
import Child from './components/Child.vue'

const list = ref(['html', 'css'])

</script>

子组件:

xml 复制代码
<!-- Child.vue -->
<template>
    <div class="hd">
        <input type="text" name="" id="" v-model="msg">
        <button @click="add">添加</button>
    </div>

</template>

<script setup>
import { ref } from 'vue';

const msg = ref('')
const props = defineProps({
    list: {
        type: Array,
        default: () => []
    }
})

const emits = defineEmits(['update:list'])

const add = () => {
    const arr = props.list
    arr.push(msg.value)
    emits('update:list', arr)
    msg.value = ''
}

</script>
    

子父通信(双向绑定)

优点:

  1. 数据同步: 使用双向绑定可以实现数据的双向同步,子组件修改数据后可以直接影响到父组件中的数据,反之亦然。

  2. 简洁明了: 双向绑定让数据流动更加清晰明了,减少了手动管理数据的复杂性。

  3. 提高开发效率: 在某些场景下,双向绑定可以减少编写大量的事件监听和触发逻辑,提高开发效率。

缺点:

  1. 数据流不清晰: 在复杂的组件结构中,双向绑定可能使得数据流变得不够清晰,增加调试和维护的难度。

  2. 难以追踪: 当数据在组件之间频繁传递和修改时,可能会难以追踪数据的变化来源,导致代码的可读性降低。

  3. 潜在的性能问题: 双向绑定会引起数据的频繁更新和DOM重新渲染,可能会对性能产生一定的影响,特别是在大型应用中。

4. 子父通信(ref)

子组件可以使用 defineExpose 暴露需要共享的值,父组件可以利用 ref 读取整个子组件对象来获取暴露的值。

父组件:

  • 获取子组件实例: 通过在子组件标签上添加 ref 属性,可以在父组件中来访问子组件的实例。
  • 直接操作子组件: 父组件可以通过 ref 获取子组件的实例,然后直接调用子组件的方法或访问子组件的数据,实现父组件对子组件的控制和操作。
xml 复制代码
<!-- Parent.vue -->
<template>
    <Child ref="childRef" />
    <div class="bd">
        <ul>
            <li v-for="item in childRef?.list">{{ item }}</li>
        </ul>
    </div>
</template>

<script setup>
import { onMounted, ref } from 'vue';
import Child from './components/Child_4.vue'

const childRef = ref(null)

</script>

子组件:

  • 提供给父组件访问的接口: 子组件可以通过 ref 方法提供自身的实例给父组件,使得父组件可以直接操作子组件。
xml 复制代码
<!-- Child.vue -->
<template>
    <div class="hd">
        <input type="text" name="" id="" v-model="msg">
        <button @click="add">添加</button>
    </div>

</template>

<script setup>
import { ref } from 'vue';

const list = ref(['html', 'css'])
const msg = ref('')

const add = () => {
    list.value.push(msg.value)
    msg.value = ''
}

defineExpose({ list }) //子组件暴露出去的数据

</script>

子父通信(ref)优点和缺点

优点:

  1. 直接访问子组件: 使用 ref 可以直接在父组件中引用和操作子组件的实例,方便进行数据传递、调用子组件方法等。

  2. 灵活性: ref 提供了一种灵活的方式来处理子组件的数据和逻辑,可以根据具体需求自由地操作子组件。

  3. 适用范围广泛: ref 不仅可以用于访问子组件,还可以用于访问 DOM 元素或其他 Vue 实例,具有较强的通用性。

缺点:

  1. 耦合性增加: 直接在父组件中操作子组件的实例可能会增加组件之间的耦合性,降低了组件的独立性和复用性。

  2. 不符合单向数据流原则: 使用 ref 可能打破 Vue.js 单向数据流的原则,使得数据流变得不够清晰,增加了代码的复杂性。

5. 父子组件通信(provide/inject)

父组件可以通过 provide 提供数据或方法,子组件可以通过 inject 注入所需的数据或方法,实现父子组件之间的通信。

父组件:

  • 使用 provide 来提供数据,这些数据将会被后代组件的 inject 所接收。
xml 复制代码
<!-- Parent.vue -->
<template>
    <div class="hd">
        <input type="text" name="" id="" v-model="msg">
        <button @click="add">添加</button>
    </div>
    <Child />
</template>

<script setup>
import { ref, provide } from 'vue';
import Child from './components/Child5.vue'

const msg = ref('')
const list = ref(['html', 'css'])

provide('list', list.value)

const add = () => {
    list.value.push(msg.value)
}
</script>

子组件:

  • 通过 inject 选项指定需要注入的数据,可以从父组件中接收到共享的数据。
xml 复制代码
<!-- Child.vue -->
<template>
    <div class="bd">
        <ul>
            <li v-for="item in list">{{ item }}</li>
        </ul>
        <Child5 />
    </div>
</template>

<script setup>
import { ref, inject } from 'vue';

const list = inject('list');
</script>

父子组件通信(provide/inject)优点和缺点:

优点:

  1. 跨层级通信: provide/inject 可以方便地实现祖先组件向后代组件的数据传递,解决了跨层级通信问题。

  2. 灵活性: provide/inject 不限制数据的传递方式,提供了一种灵活的组件通信机制。

  3. 减少嵌套组件的复杂性: 在多层嵌套的组件结构中,provide/inject 可以简化数据传递流程,减少了 props 的层层传递。

缺点:

  1. 耦合性增加: 使用 provide/inject 可能会增加组件之间的耦合性,降低了组件的独立性和复用性。

  2. 可读性较差: 在子组件中使用 inject 注入的数据需要在组件选项中指定,可读性相对较差,不如 props 直观。

相关推荐
恋猫de小郭25 分钟前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端