Vue3——组件间通信的五种常用方式

news2025/1/18 19:00:33

Vue3组件间通信的五种常用方式

写在前面

本文采用<script setup>语法糖的编写方式,比options API更自由。

<script setup>语法糖详细内容看查看文档:setup语法糖官方文档

然后我们会讲以下五种常用的组件通信方式

  • props
  • emit
  • v-model
  • refs
  • provide/inject

一、props

为了在声明props选项中获得完整的类型推导支持,我们可以使用definePropsAPI,它们将自动地在<script setup>中可用:

<script setup>
const props = defineProps({
  foo: String
})

const emit = defineEmits(['change', 'delete'])
// setup 代码
</script>
  • defineProps是只能在<script setup>中使用的编译器宏。它不需要导入,且会随着<script setup>的处理过程一同被编译掉。
  • defineProps接收与props选项相同的值。
  • defineProps在选项传入后,会提供恰当的类型推导。
  • 传入到defineProps的选项会从setup中提升到模块的作用域。因此,传入的选项不能引用在setup作用域中声明的局部变量。这样做会引起编译错误。但是,它可以引用导入的绑定,因为它们也在模块作用域内。

props是Vue3中最常见的父子通信方式,用于父组件向子组件传递数据。使用起来也比较简单,下面我们看以下demo以理解Vue3中的props

我们在父组件定义了数据,子组件声明props以接收数据。

父组件App.vue

<template>
  <div>
    <!-- 实例化子组件 -->
    <children-component :listName="list"></children-component>
  </div>
</template>

<script setup>
// 导入子组件
import ChildrenComponent from "./components/ChildComponent.vue";
import { ref } from "vue";
// data
const list = ref(["JavaScript", "HTML", "CSS"]);
</script>

<style lang="scss" scoped></style>

子组件ChildComponent.vue

<template>
  <!-- 使用props接收的来自父组件的数据 -->
  <div v-for="(item, index) in listName" :key="index">{{ item }}</div>
</template>

<script setup>
// 定义props接收父组件传来的数据
const props = defineProps({
  listName: {
    type: Array,
    default: () => [],
  },
});
</script>

<style lang="scss" scoped></style>

运行结果:数据list被成功遍历渲染。

在这里插入图片描述

二、emit

为了在声明emits选项中获得完整的类型推导支持,我们可以使用defineEmitsAPI,它们将自动地在<script setup>中可用:

<script setup>
const props = defineProps({
  foo: String
})

const emit = defineEmits(['change', 'delete'])
// setup 代码
</script>
  • defineEmits是只能在<script setup>中使用的编译器宏。它不需要导入,且会随着<script setup>的处理过程一同被编译掉。
  • defineEmits接收与props选项相同的值。
  • defineEmits在选项传入后,会提供恰当的类型推导。
  • 传入到defineEmits的选项会从setup中提升到模块的作用域。因此,传入的选项不能引用在setup作用域中声明的局部变量。这样做会引起编译错误。但是,它可以引用导入的绑定,因为它们也在模块作用域内。

emit是Vue3中最常见的父子通信方式,用于子组件向父组件传递消息[子组件调用父组件的方法]。使用起来也比较简单,下面我们看以下demo以理解Vue3中的emit

我们在父组件定义了数据和方法,子组件定义了数据并声明emit接收父组件传递的方法,子组件调用方法实现将子组件的数据通过该方法传递给父组件。

父组件App.vue

<template>
  <div>
    <!-- 实例化子组件,向子组件传递方法 -->
    <children-component @addName="add"></children-component>
  </div>
</template>

<script setup>
// 导入子组件
import ChildrenComponent from "./components/ChildComponent.vue";
import { ref } from "vue";
// 父组件data
const list = ref(["JavaScript", "HTML", "CSS"]);
// 定义父组件方法
const add = (value) => {
  list.value.push(value);
  console.log(list.value);
};
</script>

<style lang="scss" scoped></style>

子组件ChildComponent.vue

<template>
  <!-- 使用props接收的来自父组件的数据 -->
  <button @click="handleAdd(others)">按钮</button>
</template>

<script setup>
import { ref } from "vue";
const others = ref("Vue");
// 定义emit接收父组件传来的方法
const emit = defineEmits(["addName"]);
// 定义子组件的方法来使用父组件传来的方法,并将子组件的数据others传递给父组件
const handleAdd = (value) => {
  emit("addName", value);
};
</script>

<style lang="scss" scoped></style>

运行结果:点击按钮,输出父组件的数据,可以看到子组件传递来的数据Vue成功被父组件接收到了。

在这里插入图片描述

三、v-model

在介绍Vue3——v-model前,我们必须先了解一下update:属性名中的update是干啥的?其实通俗易懂一点,它就是用来同步更新父组件的值,不需要再用父组件调用自定义事件。

v-model是Vue中一个优秀的语法糖,写法:

<ChildCompont v-model:title = "title">
// 或者
<ChildCompont :modelValue = "title" @update:modelValue = "title = $event">
// 或者
<ChildCompont :title = "title" @update:title = "title = $event">

下面我们来看demo,

在子组件中我们先定义props接收父组件的数据和emits定义发送更新数据的事件,添加完成后再发送指定的事件。

父组件使用v-model绑定要发送的数据,并展示数据以监测父组件的数据是否更新。

父组件App.vue

<template>
  <ul>
    <!-- 渲染data,监测父组件数据是否发生变化 -->
    <li v-for="item in list" :key="item">{{ item }}</li>
  </ul>
  <!-- 实例化子组件,使用v-model方法向子组件传递数据 -->
  <children-component :list="list" @update:list="list = $event"
  ></children-component>
</template>

<script setup>
// 导入子组件
import ChildrenComponent from "./components/ChildComponent.vue";
import { ref } from "vue";
// 父组件data
const list = ref(["JavaScript", "HTML", "CSS"]);
</script>

<style lang="scss" scoped></style>

子组件ChildComponent.vue

<template>
  <div>
    <!-- 输入要新增的数据 -->
    <input type="text" v-model="value" placeholder="请输入" />
    <div>
      <!-- 点击按钮触发新增数据的方法 -->
      <button @click="handleAdd" type="button">add</button>
    </div>
  </div>
</template>

<script setup>
import { ref } from "vue";
const value = ref("");
// 定义props接收父组件传来的数据
const props = defineProps({
  list: {
    type: Array,
    default: () => [],
  },
});
// 定义emit发送更新list的事件
const emit = defineEmits(["update:list"]);
// 定义子组件的方法来使用父组件传来的方法,并将子组件的数据others传递给父组件
const handleAdd = () => {
  const arr = props.list; // 将父组件发送来的数据用arr接收
  arr.push(value.value); // 向arr添加输入框输入的数据
  emit("update:list", arr); // 发送更新父组件数据list的事件
  value.value = "";
};
</script>

<style lang="scss" scoped></style>

运行结果:输入要新增的list内容,点击add按钮,可以看到页面实时更新了新增的内容。

在这里插入图片描述

四、expose和ref

使用 <script setup> 的组件是默认关闭的——即通过模板引用或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。

可以通过 defineExpose 编译器宏来显式指定在 <script setup> 组件中要暴露出去的属性

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

const a = 1
const b = ref(2)

defineExpose({
  a,
  b
})
</script>

当父组件通过模板引用的方式获取到当前组件的实例,获取到的实例会像这样 { a: number, b: number } (ref 会和在普通实例中一样被自动解包)

使用API Option时,我们可以通过this.$refs.name获取指定的元素或组件,但在组合API中不行。如果我们想通过ref获取,需要定义一个同名的Ref对象,在组件挂载后可以访问。

下面我们来看demo

我们在子组件定义了数据并用defineExpose暴露,父组件中可以在通过refName?.属性名的方式使用数据。

父组件App.vue

<template>
  <ul>
    <li v-for="item in childRef?.list" :key="item">{{ item }}</li>
  </ul>
  <!-- 实例化子组件 -->
  <ChildrenComponent ref="childRef"></ChildrenComponent>
</template>

<script setup>
// 导入子组件
import ChildrenComponent from "./components/ChildComponent.vue";
import { ref } from "vue";
const childRef = ref(null);
</script>

<style lang="scss" scoped></style>

子组件ChildComponent.vue

<template>
  <div></div>
</template>

<script setup>
import { ref } from "vue";
const list = ref(["JavaScript", "HTML", "CSS"]);

defineExpose({ list });
</script>

<style lang="scss" scoped></style>

运行结果:可以看到父组件成功输出子组件的数据
在这里插入图片描述

五、provide/inject

provide/inject是 Vue 中提供的一对 API。无论层级多深,都可以实现父组件到子组件的数据传递

下面我们来看demo

父组件App.vue

<template>
  <!-- 实例化子组件 -->
  <ChildrenComponent></ChildrenComponent>
</template>

<script setup>
// 导入子组件
import ChildrenComponent from "./components/ChildComponent.vue";
import { ref, provide } from "vue";
const list = ref(["JavaScript", "HTML", "CSS"]);
provide("list", list.value);
</script>

<style lang="scss" scoped></style>

子组件ChildComponent.vue

<template>
  <ul>
    <li v-for="item in list" :key="item">{{ item }}</li>
  </ul>
</template>

<script setup>
import { inject } from "vue";
const list = inject("list");
console.log(list); // ["JavaScript", "HTML", "CSS"]
</script>

<style lang="scss" scoped></style>

运行结果:可以看到子组件成功输出父组件的数据

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高速数字信号VS射频信号,到底哪个更难设计?

一博高速先生成员&#xff1a;黄刚熟悉高速先生的小伙伴们会知道&#xff0c;我们是以研究高速数字信号为主的团队&#xff0c;从不到1G到目前在研究的112G&#xff0c;高速先生就这样一直研究过来的&#xff0c;分享的案例也大多是以高速数字信号为主的案例。最近受到我们粉丝…

golang for range 令人抓狂的面试题

1.下面这段代码能否正常结束&#xff1f; func main() {v : []int{1, 2, 3}for i : range v {v append(v, i)} } 答案&#xff1a;正常结束。 可能我们会以为程序会陷入死循环。 但是我们要明白 for range 中的v其实就是复制了一份前面定义的v切片&#xff0c;不论前面定…

Python从入门到精通第3天(循环结构的使用)

循环结构for-in循环while循环break和continue关键字练习在写程序的时候&#xff0c;一定会遇到需要重复执行某条或某些指令的场景&#xff0c;例如用程序控制机器人踢足球&#xff0c;如果机器人持球而且还没有进射门范围&#xff0c;那么我们就要一直发出让机器人向球门方向移…

免费ChatGPT接入-国内怎么玩chatGPT

免费ChatGPT中文版 OpenAI 的 GPT 模型目前并不提供中文版的免费使用&#xff0c;但是有许多机器学习平台和第三方服务提供商也提供了基于 GPT 技术的中文版模型和 API。下面是一些常见的免费中文版 ChatGPT&#xff1a; Hugging Face&#xff1a;Hugging Face 是一个开源社区…

JAVAWeb03-JavaScript

1. JavaScript 1.1 概述 1.1.1 官方文档 地址: https://www.w3school.com.cn/js/index.asp 1.1.2 基本说明 JavaScript 能改变 HTML 内容&#xff0c;能改变 HTML 属性&#xff0c;能改变 HTML 样式 (CSS)&#xff0c;能完成页面的数据验证。 js演示1.html 需要把图片拷贝…

一个注解实现WebSocket集群方案,别提有多优雅了

WebSocket大家应该是再熟悉不过了&#xff0c;如果是单体应用确实不会有什么问题&#xff0c;但是当我们的项目使用微服务架构时&#xff0c;就可能会存在问题 比如服务A有两个实例A1和A2&#xff0c;前端的WebSocket客户端C通过网关的负载均衡连到了A1&#xff0c;这个时候当…

【Java数据结构】线性表-队列

线性表-队列概念队列的使用队列模拟实现循环队列如何区分空与满双端队列 (Deque)概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出FIFO(FirstIn First Out) 入队列&#xff1a;进行插入操作的…

文章生成器写出来的原创文章

文章生成机器人 文章生成机器人是一种基于人工智能技术和自然语言处理算法的程序&#xff0c;可以自动地生成高质量、原创的文章。 文章生成机器人的优点如下&#xff1a; 提高工作效率&#xff1a;文章生成机器人能够在较短的时间内自动帮助用户生成大量的文章&#xff0c;提…

GaussDB工作级开发者认证—第三章开发设计建议

一. 数据库对象命名和设计建议 二. 表设计最佳实践 三. SQL查询最佳实践 SQL 最佳实践 - SELECT 避免对大字段执行order by&#xff0c;group by等引起排序的操作避免频繁使用count()获取大表行数慎用通配符字段 “*”避免在select目标列中使用子查询统计表中所有记录数时&…

设计模式之策略模式(C++)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 一、策略模式是什么&#xff1f; 策略模式是一种行为型的软件设计模式&#xff0c;针对某个行为&#xff0c;在不同的应用场景下&…

win下配置pytorch3d

一、配置好的环境&#xff1a;py 3.9 pytorch 1.8.0 cuda 11.1_cudnn 8_0 pytorch3d 0.6.0 CUB 1.11.0 你可能觉得pytorch3d 0.6.0版本有点低&#xff0c;但是折腾不如先配上用了&#xff0c;以后有需要再说。 &#xff08;后话&#xff1a;py 3.9 pytorch 1.12.1 cuda …

Log4j日志

log4j日志简介组成Logger 日志记录器Appender 日志目的地&#xff08;Windows下的路径分隔符&#xff09;※Layout 日志信息布局layout 指定输出的样式模板&#xff1f;layout.ConversionPattern 指定输出的每项内容及其格式顺序日志信息等级/优先级使用的Log4j的jar包代码示例…

BGP路由控制

实验要求 IP地址分配 给所有路由器按要求配置IP地址&#xff0c;AS之间使用AR编号连接作为IP&#xff0c;例如34.0.0.0/30。 在AS123中启动OSPF 启动BGP&#xff0c;并将24网段的路由宣告 R4 [r4]bgp 400 [r4-bgp]peer 24.0.0.2 as-number 123 [r4-bgp]peer 34.0.0.2 as-num…

Qt关于第三方库介绍

文章目录前言一、获取第三方库二、Makefile是什么&#xff1f;三、将第三方库添加到 Qt 项目中四、mingw和msvc的区别五、安装msvc六、安装mingw七、如何使用不同的编译器前言 本专栏的系统为&#xff1a;windows11 qt版本为&#xff1a;qt6.4.2 提示&#xff1a;以下是本篇文…

【从零开始学Skynet】实战篇《球球大作战》(五):gateway代码设计(上)

1、协议格式 在写代码之前&#xff0c;我们要先了解什么是协议&#xff0c;协议就是 “客户端向服务端发起的登录请求”&#xff0c;那么登录请求是什么样子的呢&#xff1f;这得先从TCP数据流说起&#xff0c;客户端发起的请求&#xff0c;就是一些二进制数据。 &#xff08;…

OpenCV实例(六)行人检测

OpenCV实例&#xff08;六&#xff09;行人检测1.行人检测概述2.行人检测基础实现2.1基本流程2.2实现程序2.3参数优化3.完整行人检测程序作者&#xff1a;Xiou 1.行人检测概述 行人检测是目标检测的一个分支。目标检测的任务是从图像中识别出预定义类型目标&#xff0c;并确定…

【Python】json数据解析

目录 json文件数据解析 爬虫获取王者荣耀英雄信息json数据包并解析 爬虫获取抖音视频json数据包并解析 json文件数据解析 json字符串&#xff1a;通常类似python数据类型中的列表和字典的结合&#xff0c;也可能是单独的列表或者字典格式&#xff0c;通常可以通过json模块的…

亚马逊影响搜索排名的主要因素有哪些,使用测评做排名有哪些要求?

亚马逊产品的排名越高就意味着分配的流量越多而且带来更高的销量。那主要有哪些因素影响产品的排名呢&#xff1f; 1、产品销量 产品销量反映了该产品在同类产品中的销售情况&#xff0c;该数值会在产品Listing中展示&#xff0c;平台会每小时更新一次该排行榜。在平台算法看…

【Linux】线程控制分析:如何获取线程ID?线程如何自动回收?

Linux系统中, 线程是轻量级的进程. 我们已经介绍过了线程的相关概念, 见过了线程再Linux操作系统中的存在形式. 我们知道, 进程有自己相关控制接口, 等待、创建等 而线程作为轻量级的进程, 其实也是有控制接口的. 文章目录线程控制线程的创建与回收演示获取线程idpthread_sel…

用户管理系统-自动化测试

文章目录1. 思维导图编写 Web 自动化测试用例2. 创建测试项目3. 根据思维导图设计用户管理系统自动化测试用例3.1 准备工具类3.2 测试登录页面3.3 测试用户列表页3.4 测试添加用户页3.5 测试修改用户页3.6 未登录状态4. 自动化测试项目总结4.1 自动化测试项目实现步骤4.2 当前项…