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响应式变量的值绑定到子组件的titleprop上。每当父组件中的title发生变化时,子组件也会自动更新其对应的titleprop,并反映出最新的值。: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父子组件通信方式的资料请关注脚本之家其它相关文章!
