一个全面的Vue 3组件通信演示展示

✍️ 记录

一、Vue2 中组件通信方式

  • props: 实现父子组件、子父组件、甚至兄弟组件通信
  • 自定义事件: 可以实现子父组件通信
  • 全局事件总线$bus: 可以实现任意组件通信
  • pubsub: 发布订阅模式实现任意组件通信
  • vuex: 集中状态管理容器,实现任意组件通信
  • ref: 父组件获取子组件实例 VC,获取子组件的响应式数据及方法
  • slot: 插槽(默认插槽、 具名插槽、 作用域插槽) 实现父子组件通信

二、Vue3 中组件通信方式

1. Props

Props 是 Vue3 中实现父组件向子组件传递数据的主要方式,和 Vue2 的用法类似,但在 Vue3 中对 props 的类型检测和功能扩展更加强大。

基本用法:

 

js

代码解读

复制代码

<!-- Parent --> 
<script setup lang="ts">import { ref } from 'vue'import Child from './components/Child.vue'const msg = ref('Hello from Parent')const count = ref(0)const userInfo = ref({ name: 'Zhang San', age: 18, })function increment() { count.value++ } 
</script> 
<template><div class="props-demo"><h2>Props 传值示例(readonly)</h2><div class="parent"><h3>父组件数据:</h3><p>消息:{{ msg }}</p><p>计数:{{ count }}</p><p>用户:{{ userInfo.name }} - {{ userInfo.age }}岁</p><button class="btn" @click="increment">计数+1</button></div><Child :message="msg" :counter="count" :user="userInfo" /></div>
</template>
 

js

<!-- Children --> 
<script setup lang="ts">interface Props {message?: string counter?: number user?: { name: string age: number }}defineProps <Props>() 
</script>
<template><div class="child"><h3>子组件接收到的数据:</h3><p>消息:{{ message }}</p><p>计数:{{ counter }}</p><p>用户:{{ user?.name }} - {{ user?.age }}岁</p></div> 
</template>

Note:

  • props 的核心是单向数据流,父组件的数据可以通过 props 传递给子组件,但子组件不能直接修改这些数据。
  • 如果子组件需要修改数据,通常会通过事件通知父组件,然后由父组件更新数据。
2. 自定义事件

在 Vue 框架中,事件分为两种,一种是原生的 DOM 事件,另一种是自定义事件 原生 DOM 事件可以让用户与网页进行交互,比如 click, change, mouseenter, mouseleave 等 自定义事件可以实现子组件给父组件传递数据。

自定义事件的基本用法:

在 Vue2 中,子组件通过 $emit 触发事件,父组件通过监听这些事件获取数据。在 Vue3 中,依然可以使用 emits 声明触发的自定义事件,

 

js

代码解读

复制代码

<!-- Parent --> 
<script setup lang="ts">import { ref } from 'vue'import Child from './components/Child.vue'const count = ref(0)const message = ref('')function handleIncrement(step: number) { count.value += step }function handleSendMsg(msg: string) { message.value = msg } 
</script> 
<template><div class="custom-event-demo"><h2>自定义事件示例</h2><div class="parent"><h3>父组件数据:</h3><p>计数:{{ count }}</p><p>收到的消息:{{ message }}</p></div><Child @increment="handleIncrement" @send-message="handleSendMsg" /></div>
</template>
 

js

代码解读

复制代码

<!-- Children --> 
<script setup lang="ts"> const emit = defineEmits<{ increment: [step: number] sendMessage: [msg: string] }>() function sendMsg() { emit('sendMessage', 'Hello from Child') } 
</script> 
<template> <div class="child"><h3>子组件:</h3><button class="btn" @click="emit('increment', 1)"> 通知父组件+1 </button><button class="btn" @click="emit('increment', 2)"> 通知父组件+2 </button><button class="btn" @click="sendMsg"> 发送消息 </button></div> 
</template>

Note:

  • 在 Vue2 中,组件上的所有事件,无论是原生 DOM 事件还是子组件触发的自定义事件,都会被自动绑定到组件实例上。这意味着即使是常见的 @click 事件,在 Vue2 中也是通过自定义事件实现的。
 

js

代码解读

复制代码

<ChildComponent @click="handleClick" />
  • 在 Vue3 中,事件的行为更加清晰和规范化:

    • 原生 DOM 事件:直接绑定到组件的根元素上,例如 @click 默认会绑定为 DOM 的 click 事件。
    • 自定义事件:需要声明
js<ChildComponent @click="handleClick" />

这里的 @click 默认绑定为子组件根元素的 DOM 事件,而不是子组件的自定义事件。

3. 全局事件总线

全局事件总线可以实现任意组件通信,在 vue2 中可以根据 VM 与 VC 关系推出全局事件总线。 但是在 vue3 中没有 Vue 钩子函数,也就没有 Vue.prototype,同时组合式 API 写法没有 this,如果想在 Vue3 中使用全局事件总线可以使用 mitt 插件实现。

全局事件总线是 Vue2 中实现任意组件间通信的一种常用方式。通过将一个 Vue 实例作为事件中心,可以在组件之间进行事件的发布和订阅,从而实现解耦的通信模式。

在 Vue2 中,全局事件总线通常通过 Vue.prototype 实现,将一个 Vue 实例挂载到原型上:

 

js// main.js Vue.prototype.$bus = new Vue()

在 Vue3 中使用 mitt实现全局实现总线

 
js// src/utils/eventBus.js import mitt from 'mitt' export const eventBus = mitt()

Vue2 和 Vue3 使用对比

  • 事件发布:
js// vue2 this.$bus.$emit('custom-event', payload) 
// vue3 import { eventBus } from '@/utils/eventBus' 
eventBus.emit('custom-event', { key: 'value' })
  • 事件订阅:
js// vue2 
this.$bus.$on('custom-event', (payload) => { console.log('收到数据:', payload) }) // vue3 
import { eventBus } from '@/utils/eventBus' 
eventBus.on('custom-event', (payload) => { console.log('收到数据:', payload) })
  • 事件销毁:
js// vue2 
this.$bus.$off('custom-event') // vue3 
import { eventBus } from '@/utils/eventBus' 
eventBus.off('custom-event')
4. v-model

v-model 是 Vue 中一种非常常见的双向数据绑定方式,主要用于父子组件之间的通信。在 Vue2 中,v-model 本质上是一个语法糖,绑定了一个 value 属性并监听 input 事件。 在 Vue3 中,v-model 进行了重大改进,支持多个绑定和自定义绑定名称。

Vue2 中的 v-model

在 Vue2 中,v-model 等价于:

js<!-- 父组件 --> 
<ChildComponent v-model="message" /> 
<!-- 等价于 --> 
<ChildComponent :value="message" @input="message = $event" />

Vue3 中的 v-model 改进:

  • 在 Vue3 中,v-model 不再默认绑定 value 和监听 input,而是需要显式声明绑定的 prop 和 event 名称:
js<!-- 父组件 --> 
<ChildComponent v-model="message" /> 
<!-- 子组件 --> 
<template> <input :modelValue="modelValue" @update:modelValue="$emit('update:modelValue', $event)" /> 
</template>
  • 支持多个 v-model: Vue3 支持通过自定义名称同时绑定多个 v-model:
js<!-- 父组件 --> 
<ChildComponent v-model:title="title" v-model:content="content" /> 
<!-- 子组件 --> 
<template> <input :value="title" @input="$emit('update:title', $event)" /> <textarea :value="content" @input="$emit('update:content', $event)" /> </template>
5. useAttrs

在 Vue3 中,useAttrs 是组合式 API 提供的一个工具,用于处理非 props 的属性(即未在组件 props 中显式声明的属性)。这些属性通常会通过组件传递到组件的根节点,或需要显式获取以传递给子组件。

useAttrs 提供了一种灵活的方式,使开发者可以动态访问并处理这些非 props 的属性。

使用 useAttrs 可以显式获取这些非 props 的属性,以便动态处理或传递给其他元素或子组件:

js<!-- Parent --> 
<MyButton type="primary" size="large" :disabled="false" @click="showMessage('info')" > Primary Button </MyButton> <!-- Children --> 
<ElButton v-bind="attrs"> <slot /> </ElButton>

这在构建通用组件时非常有用,例如表单组件库,可以通过 useAttrs 让组件动态适配各种传入属性。

Note:

  • 在 Vue3 中,当父组件同时通过 props 和非 props 属性(即 useAttrs 捕获的属性)传递数据到子组件时,props 的优先级更高。这是因为 props 是组件明确声明的属性,Vue 会优先将它们绑定到组件中指定的 props 上,而未声明的属性则会被归为 attrs,由 useAttrs 捕获。
6. ref 与$parent
  • ref 的用法

在 Vue3 中,ref 仍然是父组件获取子组件实例的主要方式,但实现方式有所优化。通过在父组件中为子组件添加 ref,可以访问子组件的实例,从而调用其方法或获取数据。

  • $parent 的用法

$parent 是 Vue 提供的一种访问父组件实例的方式。通过 $parent,子组件可以直接调用父组件的方法或访问父组件的数据。但需要注意,过多使用 $parent 可能会增加组件之间的耦合性。

 
js<!-- Parent --> 
<script setup lang="ts"> import { ref } from 'vue' import Child from './components/Child.vue' const childRef = ref() const count = ref(0) function increment() { count.value++ } function callChildMethod() { childRef.value?.showMessage('来自父组件的消息') } defineExpose({ increment, }) 
</script> 
<template> <div class="ref-demo"> <h2>ref、$parent示例</h2> <div class="parent"> <h3>父组件:</h3> <p>计数:{{ count }}</p> <button class="btn" @click="increment"> 计数+1 </button> <button class="btn" @click="callChildMethod"> 调用子组件方法 </button> </div> <Child ref="childRef" :counter="count" /> </div> 
</template>
js<!-- Children --> 
<script setup lang="ts"> 
import { ElMessage } from 'element-plus' 
defineProps<{ counter: number }>() 
function showMessage(msg: string) { ElMessage.success(msg) } 
function handleParentIncrement($parent: any) { // 通过 $parent 调用父组件方法 $parent.increment() ElMessage.info('已调用父组件的 increment 方法') 
} 
defineExpose({ showMessage, }) 
</script> 
<template> <div class="child"> <h3>子组件:</h3> <p>从父组件接收的计数:{{ counter }}</p> <button class="btn" @click="handleParentIncrement($parent)"> 通过$parent调用父组件 方法 </button> </div> 
</template>
7. provide 与 inject

provide 和 inject 是 Vue 提供的一种跨层级组件通信方式,常用于祖先组件向任意深度的后代组件传递数据,而无需手动逐层通过 props 和 emit 进行传递。这种方式非常适合数据共享和解耦的场景,特别是在大型项目中。

  • Provide (提供数据)

祖先组件通过 provide 提供数据,供后代组件使用。

js<!-- Parent --> 
<template> <ChildComponent /> 
</template> 
<script setup> import { provide } from 'vue'; provide('message', '来自祖先组件的消息'); 
</script>
    1. Inject (注入数据)

后代组件通过 inject 注入祖先组件提供的数据。

js<!-- Children --> 
<template> <p>{{ message }}</p> 
</template> 
<script> import { inject } from 'vue'; const message = inject('message');
</script> 
7. pinia

Pinia 是 Vue3 的官方状态管理库,是 Vuex 的轻量化和现代化替代方案。Pinia 提供了简单、直观的 API 和响应式的数据管理能力,适合解决跨组件通信和全局状态管理的问题。与 Vuex 相比,Pinia 的使用更加灵活,并充分利用了 Vue3 的组合式 API 和 Proxy 特性。

定义和使用 Store

js// src/stores/module/counter.js 
import { defineStore } from 'pinia' 
export const useCounterStore = defineStore('counter', { state: () => ({ count: 0, name: 'Pinia', }), getters: { doubleCount: (state) => state.count * 2, }, actions: { increment() { this.count++ }, }, })
  • state:存储响应式数据。
  • getters:类似于计算属性,用于派生状态。
  • actions:定义业务逻辑,用于修改状态或执行异步操作。
js
<template> <div> <p>Count: {{ counter.count }}</p> <p>Double Count: {{ counter.doubleCount }}</p> <button @click="counter.increment">Increment</button> </div> 
</template> 
<script> import { useCounterStore } from '@/stores/module/counter'; const counter = useCounterStore(); // 引入 Store 
</script>

8. 插槽

插槽的分类

Vue 中的插槽分为以下几种类型:

    1. 默认插槽
    • 父组件直接在子组件标签中插入内容,子组件使用 slot 标签渲染这些内容。
    1. 具名插槽
    • 通过指定名称区分多个插槽,以便父组件为不同的插槽传递不同内容。
    1. 作用域插槽
    • 父组件可以从子组件获取上下文数据,并动态渲染内容。
  1. 默认插槽

默认插槽是最基本的插槽形式,父组件传递的内容会直接插入到子组件中的 slot 标签处。

js<!-- 子组件 --> 
<template> <div> <slot>默认内容</slot> 
<!-- 如果父组件未传递内容,则显示默认内容 --> </div> 
</template>
js<!-- 父组件 --> 
<template> <ChildComponent> <p>这是默认插槽的内容</p> </ChildComponent> 
</template>
  1. 具名插槽

具名插槽允许子组件定义多个插槽,通过 name 属性区分,父组件可针对不同插槽传递内容。

js<!-- 子组件 --><template> <header> <slot name="header">默认标题</slot> </header> <main> <slot>默认内容</slot> </main> <footer> <slot name="footer">默认页脚</slot></footer> 
</template>
js
<!-- 父组件 -->
<template> <ChildComponent> <template #header> <h1>自定义标题</h1> </template> <template #footer> <p>自定义页脚</p> </template> </ChildComponent> 
</template>
  1. 作用域插槽

作用域插槽用于将子组件的内部数据传递到父组件,由父组件决定如何渲染这些数据。


<!-- 子组件 --> 
<template> <div> <slot :data="info"></slot> </div> 
</template> 
<script> const info = ref({ message: '这是作用域插槽的数据' }); 
</script>

<template> <ChildComponent> <template #default="{ data }"> <p>{{ data.message }}</p> </template> </ChildComponent> 
</template>

三、总结

Vue3 组件通信方式总览:

  1. 父子通信

    • Props (父 -> 子)
    • Emits (子 -> 父)
    • v-model (双向绑定)
    • ref/expose (父访问子)
    • $parent (子访问父)
  2. 跨层级通信

    • provide/inject (祖先 -> 后代)
    • 插槽 (父 -> 子内容分发)
      • 默认插槽
      • 具名插槽
      • 作用域插槽
  3. 全局通信

    • Pinia (状态管理)
    • mitt (事件总线)

选择建议:

  • 父子组件优先用 props/emits
  • 深层嵌套用 provide/inject
  • 复杂状态管理用 Pinia
  • 临时跨组件通信用 mitt

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Otter 安装流程

优质博文&#xff1a;IT-BLOG-CN 一、背景 随着公司的发展&#xff0c;订单库的数据目前已达到千万级别&#xff0c;需要进行分表分库&#xff0c;就需要对数据进行迁移&#xff0c;我们使用了otter&#xff0c;这里简单整理下&#xff0c;otter 的安装过程&#xff0c;希望对…

Web3 游戏周报(11.17 - 11.23)

回顾上周的区块链游戏概况&#xff0c;查看 Footprint Analytics 与 ABGA 最新发布的数据报告。 【11.17 - 11.23】Web3 游戏行业动态&#xff1a; 加密游戏开发商 Gunzilla Games 发推表示&#xff0c;其已与 Coinbase Ventures 达成合作并获得其投资。 国际足联将与 Mythica…

【linux学习指南】初识Linux进程信号与使用

文章目录 &#x1f4dd;信号快速认识&#x1f4f6;⽣活⻆度的信号&#x1f4f6; 技术应⽤⻆度的信号&#x1f309; 前台进程&#xff08;键盘&#xff09;&#x1f309;⼀个系统函数 &#x1f4f6;信号概念&#x1f4f6;查看信号 &#x1f320; 信号处理&#x1f309; 忽略此信…

3DEXPERIENCE软件是干什么的—3DE软件代理商微辰三维

在当今数字化转型浪潮席卷全球各个行业的大背景下&#xff0c;3DEXPERIENCE 软件宛如一颗璀璨的明星&#xff0c;闪耀在产品设计、制造以及协同创新等诸多领域。它是由达索系统公司推出的一款综合性的、功能强大的商业软件平台&#xff0c;为企业的整个产品生命周期管理带来了前…

【大数据学习 | Spark-Core】广播变量和累加器

1. 共享变量 Spark两种共享变量&#xff1a;广播变量&#xff08;broadcast variable&#xff09;与累加器&#xff08;accumulator&#xff09;。 累加器用来对信息进行聚合&#xff0c;相当于mapreduce中的counter&#xff1b;而广播变量用来高效分发较大的对象&#xff0c…

STM32编程小工具FlyMcu和STLINK Utility 《通俗易懂》破解

FlyMcu FlyMcu 模拟仿真软件是一款用于 STM32 芯片 ISP 串口烧录程序的专用工具&#xff0c;免费&#xff0c;且较为非常容易下手&#xff0c;好用便捷。 注意&#xff1a;STM32 芯片的 ISP 下载&#xff0c;只能使用串口1&#xff08;USART1&#xff09;&#xff0c;对应的串口…

MTK主板_安卓主板方案_MTK联发科主板定制开发

联发科(MTK)主板以其强大的性能和多样化的功能而受到广泛关注。该平台包括多个型号&#xff0c;例如MT6761、MT8766、MT6762、MT6765、MT8768和MT8788等&#xff0c;均配置了四核或八核64位处理器&#xff0c;主频可高达2.0GHz。采用先进的12nm工艺&#xff0c;搭载Android 11.…

信息收集(1)

学习视频引路信息收集&#xff08;1&#xff09;_哔哩哔哩_bilibili View信息收集&#xff08;1&#xff09; 分享一个漏洞挖掘平台&#xff1a;补天 以吉林通用航空职业技术学院|官网 (jlthedu.com)为目标 第一步&#xff1a;查看cdn和域名被注册的信息 可以查询域名信息的…

React(六)——Redux

文章目录 项目地址基本理解一、配置Redux store二、创建slice配置到store里并使用三、给Slice配置reducers&#xff0c;用来修改初始值 项目地址 教程作者&#xff1a;教程地址&#xff1a; 代码仓库地址&#xff1a; 所用到的框架和插件&#xff1a; dbt airflow基本理解 s…

如何利用ATECLOUD平台来实现数据报告的导出和数据分析?-纳米软件

1.数据报告导出 选择报告模板&#xff1a;ATECLOUD 平台通常会提供多种预设的数据报告模板&#xff0c;这些模板是根据不同的测试场景和需求设计的。例如&#xff0c;在电源模块测试中&#xff0c;有针对输出电压、电流、功率等基本参数的报告模板&#xff0c;也有包含纹波系数…

[ZJCTF 2019]NiZhuanSiWei

[ZJCTF 2019]NiZhuanSiWei 上面代码&#xff0c;使用get上传了三个参数&#xff0c;在text者用力恒等于&#xff0c;然后就输出&#xff0c;接着第二个参数中出现flag就输出not now&#xff0c;接着第三个参数是反序了一下输出。 ?textdata://text/plain,welcome to the zjct…

JSONCPP 数据解析与序列化

常用类接口 Json::Value 类 用于存储 JSON 数据的核心类。它支持将数据解析为对象、数组或基本类型&#xff08;如字符串、数值等&#xff09; 赋值操作符&#xff1a;Value& operator(Value other); 用于将一个 JSON 值赋给另一个 JSON 值 Json::Value value; value &…

40分钟学 Go 语言高并发:【实战】并发安全的配置管理器(功能扩展)

【实战】并发安全的配置管理器&#xff08;功能扩展&#xff09; 一、扩展思考 分布式配置中心 实现配置的集中管理支持多节点配置同步实现配置的版本一致性 配置加密 敏感配置的加密存储配置的安全传输访问权限控制 配置格式支持 支持YAML、TOML等多种格式配置格式自动…

ChatGPT 桌面版发布了,如何安装?

本章教程教大家如何进行安装。 一、下载安装包 官网地址地址&#xff1a;https://openai.com/chatgpt/desktop/ 支持Windows和MacOS操作系统 二、安装步骤 Windows用户下载之后&#xff0c;会有一个exe安装包&#xff0c;点击运行安装即可。 注意事项&#xff0c;如果Windows操…

【Electron学习笔记(二)】基于Electron开发应用程序

基于Electron开发本地应用程序 基于Electron开发本地应用程序前言正文1、创建 pages 目录2、创建 index.html 文件3 、创建 html.css 文件4 、main.js里引入页面5 、运行 start 命令6 、启用开发者模式7 、解决内容安全策略8、完善窗口行为9、配置自动重启&#xff0c;保存后自…

力扣--LCR 154.复杂链表的复制

题目 请实现 copyRandomList 函数&#xff0c;复制一个复杂链表。在复杂链表中&#xff0c;每个节点除了有一个 next 指针指向下一个节点&#xff0c;还有一个 random 指针指向链表中的任意节点或者 null。 提示&#xff1a; -10000 < Node.val < 10000 Node.random 为…

windows server 2019 启动 nginx 报错

环境 &#xff1a;windows server 2019 &#xff0c;nginx-1.19.7 背景&#xff1a; 自己经常用这个 nginx 包作为 web 服务器。今天发现 部署到 server 2019 上直接报错了。这可是原生的包&#xff0c;我啥也没改&#xff0c;怎么可能报错。而且之前在 其他服务器用都没问题…

在ASP.NET Core WebAPI 中使用轻量级的方式实现一个支持持久化的缓存组件

前言 在 WebAPI 开发中&#xff0c;缓存是一种常用的优化手段。Redis 是广泛使用的缓存解决方案&#xff0c;但在某些场景下&#xff0c;我们可能不希望引入第三方依赖&#xff0c;而是希望使用轻量级的方式实现一个支持持久化的缓存组件&#xff0c;满足以下需求&#xff1a;…

【区块链】深入理解椭圆曲线密码学(ECC)

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 深入理解椭圆曲线密码学(ECC)1. 概述2. 椭圆曲线的数学基础2.1 基本定义2.2 有限…