当前位置: 首页 > article >正文

组件通信八种方式(vue3)

一、父传子(props)

关于Props的相关内容可以参考:Props-CSDN博客

父组件通过 props 向子组件传递数据。适合简单的单向数据流。

<!-- Parent.vue -->
<template>
  <Child :message="parentMessage" />
</template>

<script setup>
const parentMessage = ref('Hello')
</script>
  • 在父组件中,通过 :message 语法将 parentMessage 传递给子组件 Child。
<!-- Child.vue -->
<template>
  <div>{{ props.message }}</div>
</template>

<script setup>
import { defineProps } from 'vue';
const props = defineProps({
      message: {
        type: String,
        required: true // 指定该 prop 为必需
      }
    });
</script>
  • 在子组件 Child 中,使用 props 选项定义接收的 message 属性
  • type 用于指定 props 的类型(如 String、Number 等)
  • required 用于指示该 prop 是否为必需

二、子传父(自定义事件)

子组件可以通过 $emit 向父组件发送事件,父组件通过v-on监听这些事件来接收数据

<!-- 绑定自定义事件xxx:实现子组件给父组件传递数据 -->
<Event2 @xxx="handler3"></Event2>    //handler3是一个你想操作的方法
  • 父组件中接收自定义事件
<button @click="sendMessage">点击触发子传父</button>

let $emit = defineEmits(['xxx']);   //利用defineEmits方法返回函数触发自定义事件
sendMessage() {
      $emit('childMessage', 'Hello from Child!');
}
  • 子组件中:点击按钮触发“向父组件传递信息”的操作

三、v-model组件通信(父子组件数据同步)

vue3.4之前:

1、前言:通过 v-model,父组件可以将数据传递给子组件,子组件可以在内部修改这些数据,并将更新后的值同步回父组件

2、使用 v-model 实现数据同步的步骤:

  • 父组件传递数据:父组件使用 v-model 将数据传递给子组件。
  • 子组件定义 modelValue:子组件需要定义 modelValue 属性来接收来自父组件的数据。
  • 子组件触发更新:子组件通过 $emit 触发 update:modelValue 事件,将修改后的数据发送回父组件。

3、代码示范:

//父组件中
<Child v-model:value="value" />
//子组件中
<template>
    <input v-model="inputValue" @input="updateValue" />  //@input 是一个原生 DOM 事件,表示用户在输入框中输入内容时触发的事件。
</template>

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

// 定义 props,并接收父组件传递的值
const props = defineProps<{
  modelValue: string; 
}>();

// 定义事件
const emit = defineEmits<{
  (e: 'update:modelValue', value: string): void; 
}>();

// 创建响应式变量
const inputValue = ref(props.modelValue); 

// 监听 props 的变化,确保 inputValue 始终与 modelValue 同步
watch(
  () => props.modelValue,
  (newValue) => {
    inputValue.value = newValue;
  }
);

// 更新值并触发更新事件
const updateValue = () => {
  emit('update:modelValue', inputValue.value);
};
</script>

注:其主要实现原理还是利用了props和自定义事件的组合使用,v-model只是帮我们同步了数据和方法

vue3.4之后(使用 defineModel())

1、defineModel():

该函数简化了 v-model 的使用,自动处理 modelValue 的接收和 update:modelValue 事件的发出。

2、使用:

<!-- Parent.vue -->
<Child v-model="countModel" />
  • 在父组件中,使用 v-model 将 countModel 绑定到子组件 Child 的 model(这是 defineModel() 中定义的)。
  • 当父组件的 countModel 变化时,子组件将自动接收到更新。
<!-- Child.vue -->
<script setup>
const model = defineModel()

function update() {
  model.value++
}
</script>

<template>
  <div>Parent bound v-model is: {{ model }}</div>
  <button @click="update">Increment</button>
</template>
  • defineModel() 函数用于定义 v-model 的数据绑定。在这里,它会自动接收来自父组件的 countModel 的值,并将其存储在 model 中。
  • model 变量是响应式的,因此,当父组件的 countModel 发生变化时,model 也会更新。

3、数据流动

从父组件到子组件:父组件的 countModel 值通过 v-model 传递给子组件,并被 defineModel() 接收并存储在 model 中。

从子组件到父组件:

  • 当用户在子组件中点击按钮,update() 方法会增加 model.value 的值。
  • -由于 defineModel() 自动处理了 update:modelValue 事件,这样子组件在更新 model.value 时,会自动触发父组件 countModel 的更新。

4、v-model的参数

组件上的v-model也可以接受一个参数:

<MyComponent v-model:title="bookTitle" />

在子组件中,通过将字符串作为第一个参数传递给defineModel()来支持相应的参数:

<!-- MyComponent.vue -->
<script setup>
const title = defineModel('title')
</script>

<template>
  <input type="text" v-model="title" />
</template>

5、多个v-model绑定

组件上的每一个v-model都会同步不同的prop,而无需额外的选项:

 <UserName
  v-model:first-name="first"
  v-model:last-name="last"
/>
<!-- Username.vue -->
<script setup>
const firstName = defineModel('firstName')
const lastName = defineModel('lastName')
</script>

<template>
  <input type="text" v-model="firstName" />
  <input type="text" v-model="lastName" />
</template>

6、处理 v-model 修饰符

想创建一个自定义的修饰符来实现某种功能,例:将 v-model 绑定输入的字符串值第一个字母转为大写

<MyComponent v-model.capitalize="myText" />

为了能够基于修饰符选择性地调节值的读取和写入方式,我们可以给 defineModel() 传入 get 和 set 这两个选项。

<script setup>
const [model, modifiers] = defineModel({
  set(value) {
    if (modifiers.capitalize) {
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
    return value
  }
})
</script>

<template>
  <input type="text" v-model="model" />
</template>

7、带参数的v-model修饰符

这里用例子展示了如何在使用多个不同参数的v-model时使用修饰符:

<UserName
  v-model:first-name.capitalize="first"
  v-model:last-name.uppercase="last"
/>
<script setup>
const [firstName, firstNameModifiers] = defineModel('firstName')
const [lastName, lastNameModifiers] = defineModel('lastName')

console.log(firstNameModifiers) // { capitalize: true }
console.log(lastNameModifiers) // { uppercase: true }
</script>

总结

Vue 3.4 后,使用 v-model 进行组件通信的方式更加简洁和高效,提升了代码的可读性和维护性。

四、全局事件总线(mitt)

背景:在 Vue 3 中,虽然不再推荐使用全局事件总线(Event Bus)作为组件之间通信的主要方式,但仍然可以通过一些方法实现类似的功能。全局事件总线的主要目的是在不同组件之间传递事件,而不通过父子组件的直接通信。

使用:

1、安装 mitt:

mitt 是一个轻量级的事件总线库,可以方便地在 Vue 3 中使用。

npm install mitt
2、创建事件总线:
// eventBus.js
import mitt from 'mitt';

const eventBus = mitt();

export default eventBus;
3、在组件中使用事件总线:
<!-- ComponentA.vue -->


<script setup lang="ts">
import eventBus from './eventBus';

const sendMessage = () => {
  eventBus.emit('xxx', 'Hello from Component A!');
};
</script>
<!-- ComponentB.vue -->

<script setup lang="ts">
import {onMounted, onUnmounted } from 'vue';
import eventBus from './eventBus';


const receiveMessage = (msg: string) => {
  message.value = msg;
};

 //在事件总线中注册一个事件监听器,以便在特定事件发生时执行相应的回调函数
onMounted(() => {
  eventBus.on('xxx', receiveMessage);
});

//清理事件监听,避免内存泄漏 
onUnmounted(() => {
  eventBus.off('xxx', receiveMessage);
});
</script>

五、使用 provide/inject(隔辈通信)

使用props实现逐级透传 VS 使用provide-inject

      VS

provide() 函数:为组件后代提供数据

<script setup>
import { provide } from 'vue'

provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
</script>

注:如果不使用 <script setup>,请确保 provide() 是在 setup() 同步调用的
参数:

  • 注入名:后代组件用注入名来查找期望注入的值;类型:字符串/Symbol
  • 提供的值:可以是任意类型的,包括响应式的状态

inject:注入上层组件提供的数据

<script setup>
import { inject } from 'vue'

const message = inject('message')
</script>

注:如果提供的值是一个 ref,注入进来的会是该 ref 对象,而不会自动解包为其内部的值。这使得注入方组件能够通过 ref 对象保持了和供给方的响应性链接。

六、useAttrs组件通信

1、useAttrs 的基本概念:

  • 用途:useAttrs 允许子组件访问和操作父组件传递的属性和事件,而无需显式地定义这些属性。
  • 场景:常用于构建高度可复用和灵活的组件,比如包装器组件或 UI 库组件。

2、基本用法:

<!-- MyButton.vue -->
<template>
  <button v-bind="attrs">

  </button>
</template>

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

const attrs = useAttrs(); // 获取父组件传递的属性


</script>                        
<!-- Parent.vue -->
<template>  
    <MyButton type="submit" class="btn" @click="handleSubmit">提交  </MyButton>
</template>

type="submit" class="btn"是传递的属性:子组件可以通过 useAttrs 访问这些属性,并将它们应用于其内部的 DOM 元素

@click="handleSubmit":这是一个事件监听器,当子组件中的按钮被点击时,会调用父组件中的 handleSubmit 方法。

3、详细解释:

访问属性:

useAttrs():

  • 返回一个 Reactive 对象,包含所有传递给当前组件的非响应式属性。
  • 这些属性可以使用 v-bind 绑定到子组件的 DOM 元素上。

事件处理:

事件传递:

  • 子组件可以直接使用 @eventName 语法捕获父组件传递的事件。
  • 此外,子组件可以将事件处理逻辑封装在自己的方法中,进一步控制事件的处理。

4、总结

useAttrs 只获取非响应式属性。如果需要响应式数据,仍需使用 props。

七、Pinia

pinia的有关知识可以去参考:pinia(vue3)-CSDN博客

Pinia 是一个用于状态管理的库,通常用于替代 Vuex。它提供了一种简单且直观的方式来管理应用的全局状态,并支持组件之间的通信。

八、ref与$parent

  • ref在父组件中获取子组件实例对象
  • $parent可以在子组件内部获取父组件实例对象

以下的示例是从从父组件中控制子组件:

<template>
  <div>
    <h1>父组件计数: {{ count }}</h1>
    <Child ref="child" />
    <button @click="increment">增加</button>
  </div>
</template>

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

const count = ref(0); // 父组件的响应式数据
const child = ref(null); // 用于存储子组件的引用

const increment = () => {
  count.value++; // 增加父组件的计数
};

// 可以通过子组件的方法来更新父组件的状态
const updateFromChild = () => {
  // 调用子组件的某个方法
  child.value.updateCount();
};
</script>

子组件:

<template>
  <div>
    <h2>子组件</h2>

  </div>
</template>

<script setup>


const updateCount = () => {
    console.log('更新')
}
</script>

总结:

在 Vue 中,使用 ref 和$parent 是一种实现组件通信的方式,虽然这种方式在某些情况下有效,但通常不建议使用,因为它可能导致代码的耦合性增加和可维护性降低。


http://www.kler.cn/a/369336.html

相关文章:

  • 【论文阅读】PGAN
  • Spring Boot植物健康系统:智慧农业的新篇章
  • JavaScript 的 axios 实现文件下载功能
  • 查看spring boot 的版本情况
  • MyBatis缓存详解(一级缓存、二级缓存、缓存查询顺序)
  • STM32之外部中断(实验对射式传感器计次实验)
  • 2024年下教师资格证面试报名详细流程❗
  • Vue应用中使用xlsx库实现Excel文件导出的完整指南
  • 详解Java之Spring MVC篇一
  • uniapp路由权限拦截守卫
  • 24下软考信息系统监理师,快背,都是精华知识点!
  • spring高手之路
  • react18中的受控与非受控组件及ref的使用
  • 配置 SSH 无需密码连接服务器及为 IP 指定自定义域名
  • arthas使用 笔记
  • 2025选题|基于Hadoop的物品租赁系统的设计与实现
  • windows 训练yolov8官方数据集
  • SpringBoot poi-tl通过模板占位符生成word文件
  • 奥哲与中建三局集团有限公司战略签约
  • 美畅物联丨视频上云网关如何配置上级联网云平台
  • nacos安装与配置
  • 存储引用服务(OSS)Minio 环境搭建
  • 最新版的 Git+VS Code同步版本管理实践
  • 运维面试汇总
  • [JAVAEE] 面试题(一) - 锁策略, synchronized的详细介绍
  • 标题点击可跳转网页