Vue3中父子组件之间相互通信的方式详解
作者:Danta
前言
父子组件通信,作为Vue应用开发中不可或缺的一部分,是实现数据流动、事件触发以及组件间互动的关键机制。无论是简单的属性传递,还是复杂的交互逻辑,掌握这一技能对于构建富有层次感和互动性的用户界面至关重要。通过学习如何有效地利用props
进行数据下行传递,使用emit
触发自定义事件,以及借助ref
直接操作子组件。本文将详细探讨Vue 3中的父子组件通信,帮助你深入了解并掌握这些核心概念。
父传子
使用Props传递数据和方法
在Vue中,父组件向子组件传递数据最常用的方法是通过props
。props
允许父组件以一种声明式的方式向下传递数据到子组件。这种方式不仅简化了数据流的管理,还确保了组件之间的单向数据绑定,使得状态更易于追踪和调试。
代码模块
App.vue
<script setup> import ChildComponent from './components/ChildComponent.vue' import { ref } from 'vue' const title=ref("来自父组件的消息") const method =()=>{ console.log("来自父组件的方法") } </script> <template> <div> <h2>父组件</h2> <ChildComponent :title="title" :parentmethod="method" /> </div> </template> <style scoped> </style>
解析:
const title
:创建了一个响应式的引用(ref
),它的值是“来自父组件的消息”。这个引用可以被传递给子组件,并且如果在父组件中修改了它的值,子组件会自动更新。const method
:定义了一个简单的方法,当它被执行时,会在浏览器的控制台输出一条信息。:title="title"
的意思就是:将父组件中的title
响应式变量的值绑定到子组件的title
prop上。每当父组件中的title
发生变化时,子组件也会自动更新其对应的title
prop,并反映出最新的值。:parentmethod="method"
同理
ChildComponent.vue
<template> <div> 在子组件中: {{props.title}} <button @click="props.parentmethod">子组件调用父组件的方法</button> </div> </template> <script setup> import { defineProps, ref } from 'vue' const props=defineProps({ title:{ type:String, required:true }, parentmethod:{ type:Function, required:true } }) </script> <style scoped> </style>
- 接收
props
:子组件通过defineProps
声明了它期望从父组件接收两个props
:title
和parentmethod
。根据填写required
的true|flase
,是否判断必需传入。这两个props
都是必需的,并且有type来定义明确的类型。 - 显示
props
:在模板中,子组件使用{{ props.title }}
来显示父组件传递过来的标题。 - 调用父组件方法:子组件还包含了一个按钮,其点击事件被绑定到了
props.parentmethod
。这意味着当用户点击按钮时,子组件会触发父组件中定义的方法。由于parentmethod
是从父组件传入的一个函数引用,因此它会在父组件的作用域内执行。 - 响应性:因为
title
是一个响应式的prop
,如果父组件更新了它的值,子组件也会自动重新渲染以反映最新的标题。
效果:
子传父
使用Emit触发自定义事件
子组件与父组件通信的主要方式之一是通过emit
触发自定义事件。当子组件想要通知父组件某个特定事件发生时,它可以调用emit
来触发一个命名事件,并可以选择性地传递额外的数据。 App.vue
<script setup> import ChildComponent from './components/ChildComponent.vue' import { ref } from 'vue' const title=ref("来自父组件的消息") const method =()=>{ console.log("来自父组件的方法") } const messageFromChild=ref("") const handleChildMessage = (message) => { console.log('来自子组件的消息:', message); messageFromChild.value=message // 在这里可以处理子组件发送的消息 }; </script> <template> <div> <h2>父组件</h2> <ChildComponent :title="title" :parentmethod="method" @child-message="handleChildMessage"/> <p>来自子组件的消息:{{messageFromChild}}</p> </div> </template> <style scoped> </style>
@child-message="handleEvent"
自定义事件名称 attrs + 处理函数child-message
:这是你为子组件定义的一个自定义事件名称。它不是内置的DOM事件(如click
、input
等),而是由开发者根据需求命名的。通过这个名称,子组件可以触发特定事件并向父组件传递数据。handleEvent
:这是父组件中定义的一个方法,用来处理来自子组件的消息。当你在父组件模板中使用@child-message="handleEvent"
时,实际上是在说:“每当子组件触发child-message
事件时,请调用handleEvent
方法”。
ChildComponent.vue
<template> <div> 在子组件中: {{props.title}} <hr> <button @click="props.parentmethod">子组件调用父组件的方法</button> <hr> <button @click="childMessage">子组件给父组件发送数据</button> </div> </template> <script setup> import { defineProps, ref, defineEmits, } from 'vue' const props=defineProps({ title:{ type:String, required:true }, parentmethod:{ type:Function, required:true } }) const emit = defineEmits(['child-message']) const childMessage = () => { emit('child-message', '我是子组件'); }; </script> <style scoped> </style>
解析:
const emit = defineEmits(['child-message'])
defineEmits
:这是Vue Composition API的一部分,用于定义子组件可以触发的自定义事件列表。它返回一个函数emit
,该函数可以用来触发这些事件。['child-message']
:这里是一个字符串数组,列出了所有可以由子组件触发的自定义事件名称。在这个例子中,我们只定义了一个名为child-message
的事件,如果有多个事件,可以通过数组的形式添加。
const childMessage....
emit('child-message', '我是子组件')
:调用emit
函数来触发一个名为child-message
的自定义事件,并传递一个字符串'我是子组件'
作为参数。这个消息会被发送给监听了child-message
事件的父组件。
效果:
图解:
当我们实现完子组件向父组件,传递信息后,那么长的帅的读者就要问了?怎么向父组件传递方法呢?
使用ref实现子组件对父组件的传递
创建响应式引用:
大家都知道ref
可以用来创建一个响应式的变量,该变量可以被绑定到模板中的元素或组件上。当这个变量的值发生变化时,视图会自动更新。
import { ref } from 'vue' const count = ref(0)
访问子组件实例:
当你需要直接与子组件进行交互时(比如调用子组件的方法或访问它的属性),可以通过给子组件添加 ref
属性来获取子组件的实例。
代码:
我们可以先看子组件向父组件输出了什么? parent组件:
<template> <div> <Child ref="comp" /> <button @click="handlerClick">按钮</button> </div> </template> <script setup> import { ref } from 'vue' import Child from './Child.vue' const comp = ref(null) // 标记DOM 元素 null 组件没用挂载,DOM 也不在 const title = ref('hello') // 标记数据 const handlerClick = ()=>{ console.log(comp,comp.value) console.log( comp.value.childName) comp.value.someMethod() } </script> <style scoped> </style>
child组件:
<template> <div> Child </div> </template> <script setup> import { defineProps, defineEmits, defineExpose, ref } from 'vue' defineExpose({ childName:"这是子组件的属性", someMethod:()=>{ console.log('这是子组件的方法') } }) </script> <style scoped> </style>
解析:
重点:
<Child ref="comp" />
:这里定义了一个子组件Child
,并通过ref
属性给它指定了一个名为comp
的引用。这使得父组件可以在JavaScript中直接访问这个子组件实例,调用子组件的方法和属性。defineExpose({ ... })
:这是Vue Composition API的一部分,用来明确哪些属性或方法应该暴露给父组件。在这个例子中,我们暴露了两个成员:childName
:一个字符串,作为子组件的一个公开属性。someMethod
:一个函数,作为子组件的一个公开方法,可以被父组件调用。
最后在父组件就可以通过
comp.value.
,调用方法或者属性。
运行机制
挂载阶段:当父组件首次渲染时,子组件也会一同被挂载。此时,
comp.value
会被更新为指向子组件的实例。点击按钮:用户点击按钮后,
handlerClick
函数被执行。由于此时子组件已经挂载完成,因此可以通过comp.value
访问到子组件实例,并且可以安全地调用它的公开属性和方法。输出结果:
- 控制台首先会打印出
comp
引用及其当前值(即子组件实例)。 - 接着会打印出子组件的
childName
属性值:“这是子组件的属性”。 - 最后,调用子组件的
someMethod
方法,在控制台上输出:“这是子组件的方法”。
- 控制台首先会打印出
效果:
总结:
- 父传子 - 使用
props
传递数据和方法:父组件可以通过props
将数据和方法传递给子组件,这种方式不仅简化了数据流的管理,还确保了组件之间的单向数据绑定,使得状态更易于追踪和调试。 - 子传父 - 使用
emit
触发自定义事件:子组件可以通过emit
触发自定义事件来通知父组件某些特定事件的发生,并可以选择性地传递额外的数据。父组件可以通过监听这些事件来做出相应的反应。 - 使用
ref
直接操作子组件实例:当需要直接与子组件进行交互时,比如调用子组件的方法或访问它的属性,可以通过给子组件添加ref
属性来获取子组件的实例。借助defineExpose
,可以有选择性地暴露子组件的属性和方法给父组件。
以上就是Vue3中父子组件之间相互通信的方式详解的详细内容,更多关于Vue3父子组件通信方式的资料请关注脚本之家其它相关文章!