组件通信八种方式(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 是一种实现组件通信的方式,虽然这种方式在某些情况下有效,但通常不建议使用,因为它可能导致代码的耦合性增加和可维护性降低。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/898788.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2018年-2020年 计算机技术专业 程序设计题(算法题)实战_数组回溯法记录图的路径

阶段性总结&#xff1a; 树的DFS存储一条路径采用定义一个栈的形式 图的DFS和BFS&#xff0c;存储一条路径 采用数组回溯法 文章目录 2018年1.c语言程序设计部分2. 数据结构程序设计部分 2019年1.c语言程序设计部分2. 数据结构程序设计部分 2020年1.c语言程序设计部分2. 数据结…

基于微信小程序的智能校园社区服务推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

Kimi 自带的费曼学习器,妈妈再也不用担心我的学习了

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 AI工具集1&#xff1a;大厂AI工具【共23款…

【经管】比特币与以太坊历史价格数据集(2014.1-2024.5)

一、数据介绍 数据名称&#xff1a;比特币与以太坊历史价格数据集 频率&#xff1a;逐日 时间范围&#xff1a; BTC&#xff1a;2014/9/18-2024/5/1 ETH&#xff1a;2017/11/10-2024/5/1 数据格式&#xff1a;面板数据 二、指标说明 共计7个指标&#xff1a;Date、Open…

安装vue发生异常: idealTree:nodejs: sill idealTree buildDeps

一、异常 C:\>npm install vue -g npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIREDnpm ERR! request to https://registry.npm.taobao.org/vue failed, reason: certificate has expired 二、原因 请求 https://registry.npm.taobao.org 失败&#xff0c;证…

通义灵码:融合创新玩法与探索,重塑LeetCode解题策略

文章目录 关于通义灵码安装指南 通义灵码与LeetCode的结合通义灵码给出优化建议通义灵码给出修改建议通义灵码给出自己的思路 总结 大家好&#xff0c;欢迎大家来到工程师令狐小哥的频道。都说现在的时代是AI程序员的时代。AI程序员标志着程序员的生产力工具已经由原来的搜索式…

JavaSE之String类

文章目录 一、String类常用的构造方法二、常见的四种String对象的比较1.使用比较2.使用equals()方法比较3.使用compareTo()方法比较4.使用compareToIgnoreCase()方法比较 三、字符串的查找四、字符串的转化1.数字和字符串间的转化2.大小写转化3.字符串和数组间的转化 五、字符串…

grafana 配置prometheus

安装prometheus 【linux】麒麟v10安装prometheus监控&#xff08;ARM架构&#xff09;-CSDN博客 登录grafana 访问地址&#xff1a;http://ip:port/login 可以进行 Grafana 相关设置&#xff08;默认账号密码均为 admin&#xff09;。 输入账户密码 添加 Prometheus 数据源…

Codeforces Round 979 (Div. 2)

A. A Gift From Orangutan 题意&#xff1a; 思路&#xff1a; 贪心 模拟 重新排列的数组 -> 最大的元素放第一个位置 &#xff0c;最小的元素放第二个位置 #include<bits/stdc.h> using namespace std; #define lowbit(x) ( x & -x )#define int long long ty…

人类末日?Hinton预言AI恐将夺取地球控制权!

图片来源&#xff1a;Youtube Z Highlights&#xff1a; AI会变得比人类更聪明。我们必须担心它们会想从我们手中夺取控制权&#xff0c;这是我们应该认真思考的问题。 使用AI制造自动化致命武器的风险并不取决于AI是否比我们聪明。这与AI本身可能失控并试图接管的风险是完全…

[论文笔记]HERMES 3 TECHNICAL REPORT

引言 今天带来论文HERMES 3 TECHNICAL REPORT&#xff0c;这篇论文提出了一个强大的工具调用模型&#xff0c;包含了训练方案介绍。同时提出了一个函数调用标准。 为了简单&#xff0c;下文中以翻译的口吻记录&#xff0c;比如替换"作者"为"我们"。 聊天模…

嵌套div导致子区域margin失效问题解决

嵌套div导致子区域margin失效问题解决 现象原因解决方法 现象 <div class"prev"></div> <div class"parent"><div class"child"></div><div class"child"></div> </div> <div cl…

HCIP到底需要考哪几门?821和831都要考吗?

相对于华为认证中的HCIE&#xff0c;HCIP难度较低比较容易获得。 对于许多准备考HCIP认证的朋友来说&#xff0c;了解考试要求和内容是成功的关键第一步。 经常问的问题上次刚梳理了一波价格&#xff0c;还没看的看这里→《HCIP考证多少钱&#xff1f;HCIP认证深度解析》 今天再…

效果不错的论文介绍:Im2Flow2Act:-跨领域机器人操控技术

Im2Flow2Act: 跨领域机器人操控技术 简介 今天介绍一个比较惊艳的论文&#xff0c;Im2Flow2Act&#xff0c;可以预测应该怎么移动图象中的物体预测移动方法完成需要执行的动作任务。 Im2Flow2Act 是一个基于学习的机器人操控框架&#xff0c;旨在通过多种数据源为机器人提供操…

《深度学习》OpenCV EigenFaces算法 人脸识别

目录 一、EigenFaces算法 1、什么是EigenFaces算法 2、原理 3、实现步骤 1&#xff09;数据预处理 2&#xff09;特征提取 3&#xff09;构建模型 4&#xff09;识别 4、优缺点 1&#xff09;优点 2&#xff09;缺点 二、案例实现 1、完整代码 运行结果&#xff…

Star Tower:智能合约的安全基石与未来引领者

在区块链技术的快速发展中&#xff0c;智能合约作为新兴的应用形式&#xff0c;正逐渐成为区块链领域的重要组成部分。然而&#xff0c;智能合约的可靠性问题一直是用户最为关心的焦点之一。为此&#xff0c;Star Tower以其强大的技术实力和全面的安全保障措施&#xff0c;为智…

算法之随机数

概述 用Java的Math.random()方法生成随机数。此方法为真随机。 代码 public static void main(String[] args) {int size 100;int cycle 1000000;int count 0;int target 1;for(int i 0; i < cycle; i){int r (int) (Math.random() * size);if(r target){count;}}S…

微信小程序文本收起展开

这里写自定义目录标题 微信小程序文本收起展开常见问题的梯形背景框 微信小程序文本收起展开 参考 https://juejin.cn/post/6963904955262435336 <!-- 常见问题解答 --><view classcontentBottom><view classBottomFirst><text id0 data-id0 class&quo…

SSM框架实战小项目:打造高效用户管理系统 day3

前言 在前两篇博客中&#xff0c;后台已经搭建完毕&#xff0c;现在需要设计一下前端页面 webapp下的项目结构图 创建ftl文件夹&#xff0c;导入css和js 因为我们在后台的视图解析器中&#xff0c;设置了页面解析器&#xff0c;跳转路径为/ftl/*.ftl&#xff0c;所以需要ftl文件…

SpringBoot日常:封装redission starter组件

文章目录 逻辑实现POM.xmlRedissionConfigRedissionPropertiesRedissionUtilsspring.factories 功能测试application.yml配置POM.xmlTestController运行测试 本章内容主要介绍如何通过封装相关的redission连接配置和工具类&#xff0c;最终完成一个通用的redission starter。并…