前言
vue3的组件通信和vue2相比在语法上会有些差距,且vue3有的通信方式也在功能上比vue2更加完善,比如provide/inject,vue3相比vue2多了支持响应式的功能。这里主要列出vue3的组件通信,且使用vue3的组合式API风格来实现。
提示:以下是本篇文章正文内容,下面案例可供参考
一、父子组件通信
1.父组件向子组件通信
(1)父组件传递:
只需要在引入的子组件标签上,传入(子组件那里已经定义的)参数名对应的值即可。
语法:
<template><子组件名称 :参数名1="值" :参数名2="值"></子组件名称></template>
(2)子组件接收:
使用props关键字。在vue2(选项式API)中,props直接定义在最外层和data、methods同级,而vue3的组合式api中则需要通过defineProps来定义,
即语法为:(语法糖形式)
const props = defineProps({ 参数名1: 参数类型, 参数名2: 参数类型 });
如果是setup()形式,则和setup()同级,写法和选项式api一致,一般写setup上面:
export default {
props: {参数1: 参数值},
setup(props) {
// setup() 接收 props 作为第一个参数
console.log(props.参数1)
}
}
当然defineProps中不仅可以传对象也可以传字符串数组,一般是传递对象,因为需要定义参数类型。
使用时语法:props.参数名1
整体示例:
子组件:
ChildComponent.vue
<script setup>
import { ref } from 'vue';
const props = defineProps({
title: {
type: String,
default: '默认标题',
},
btnFun: {
type: Function,
default: () => {},
},
});
const inputValue = ref('');
</script>
<template>
<div>
<h2>{{ props.title }}</h2>
<a-button type="primary" @click="props.btnFun">完成</a-button>
<a-input v-model:value="inputValue" placeholder="请输入" />
</div>
</template>
父组件:
<template>
<child-component :title="测试标题" :btn-fun="() => { console.log('按钮被点击'); }">
</child-component>
</template>
其中ChildComponent和btnFun可以是原值,也可以是“-”分割后的值,都可以识别。
2.子组件向父组件通信
使用emit,vue3定义emit,使用defineEmits,
子组件里:
定义语法:
const emit = defineEmits(['child-event1','child-event2']);
setup()形式定义位置同1中的defineProps。
触发语法:
emit('child-event1',要传递的参数)
父组件里:
接收语法:
<子组件名 @child-event1='本地定义函数名'/>
整体例子:
<!-- 父组件 -->
<template>
<ChildComponent :message="parentMsg" @child-event="handleEvent" />
</template>
<script setup>
import { ref } from 'vue';
const parentMsg = ref('来自父组件的数据');
const handleEvent = (payload) => {
console.log('子组件传来:', payload);
};
</script>
<!-- 子组件:ChildComponent -->
<template>
<button @click="$emit('child-event', '触发事件')">发送数据</button>
</template>
<script setup>
const props = defineProps({
message: String
});
const emit = defineEmits(['child-event']);
</script>
3.ref父组件直接操作子组件通信。
vue3中的语法,父组件:
<template>
<子组件名称 ref="ref名称"/>
</template>
<script setup>
import { ref } from 'vue';
const 'ref名称' = ref(null); // 父组件可以通过'ref名称'拿到子组件上的方法和data等数据
</script>
示例:
<!-- 父组件 -->
<template>
<ChildComponent ref="childRef" />
</template>
<script setup>
import { ref, onMounted } from 'vue';
const childRef = ref(null);
onMounted(() => {
childRef.value.someMethod(); // 调用子组件方法
});
</script>
进阶:如果是遇到多个子组件按需加载的情况,则此时若要通过ref获取到子组件的信息,则子组件还需加上 defineExpose
。
场景:
is里面循环的子组件(StepOne、StepTwo)里需要加上:
二、跨代通信
1. 跨层级通信
使用provide/inject函数, 其中provide为后代组件提供数据,需要接收的后代组件则是通过inject去接收数据。
语法:
祖先组件发送数据:provide('注入名', 要传递的参数);
后代接收数据:inject('注入名',要接收的参数);
使用示例:
<!-- 祖先组件 -->
<script setup>
import { provide, ref } from 'vue';
const theme = ref('dark');
provide('theme', theme); // 提供数据
</script>
<!-- 深层子组件 -->
<script setup>
import { inject } from 'vue';
const theme = inject('theme'); // 注入数据
console.log(theme.value); // 'dark'
</script>
另:如果没有使用setup语法糖,provide(/inject)要在setup()函数内调用:
import { provide } from 'vue'
export default {
setup() {
provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
}
}
进阶:
provide第二个参数,即要传递的参数值可以是任意类型,包括响应式的状态,比如一个 ref;
provide可以传递多个,后代按照注入名字接收,如果有重复的则以离得最近的父代为准。
import { ref, provide } from 'vue'
const count = ref(0);
function updateCount() {
count ++;
}
provide('key', { count, updateCount });
后代接收时:
<script setup>
import { inject } from 'vue'
const { count, updateCount } = inject('location');
</script>
<template>
<button @click="updateCount">{{ count }}</button>
</template>
2.事件总线通信
使用mitt工具:
下载:npm install mitt
创建事件总线模块:
event-bus.js
import mitt from 'mitt';
const emitter = mitt();
export default emitter;
发送事件组件:
SenderComponent.vue
<template>
<button @click="sendMessage">发送消息</button>
</template>
<script setup>
import emitter from './event-bus';
const sendMessage = () => {
emitter.emit('custom-event', {
message: '来自SenderComponent的消息',
timestamp: new Date().toISOString()
});
};
</script>
接收事件组件:
ReceiverComponent.vue
<template>
<div>
<p>接收到的消息: {{ receivedMessage }}</p>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import emitter from './event-bus';
const receivedMessage = ref('等待消息...');
const handleEvent = (payload) => {
receivedMessage.value = payload.message;
console.log('接收到事件:', payload);
};
onMounted(() => {
// 注册事件监听
emitter.on('custom-event', handleEvent);
});
onUnmounted(() => {
// 移除事件监听,防止内存泄漏
emitter.off('custom-event', handleEvent);
});
</script>
总结
以上用了大概五种方式来阐述组件之间的通信,这些在日常开发中比较常见,对于vue入门来说是需要去掌握并灵活运用的,对于子父组件一开始会有混乱不清的情况,这种在以后的练习和熟悉中会逐渐分清。