vue3父子组件间传参通信
@[TOC] 父子组件通信
前言
本文主要是记录Vue3在setup语法糖下的父子组件间通信的四种方式
Vue3+TypeScript
一、父传子— props
父组件传值给子组件主要是由父组件为子组件通过v-bind绑定数值,而后传给子组件;子组件则通过defineProps接收使用。
父组件: 父组件中给要传给子组件的属性type直接赋值
<el-dialog :close-on-click-modal="false" :title="dialog.title" v-model="dialog.visible" width="1000px" top="15px"
@close="cancel">
<form-children type="create" @changeVisible="handleVisible" ref="formChildrenRef"/>
</el-dialog>
子组件: 子组件里的props定义从父组件拿过来的属性名type, 从而拿到父组件传过来的属性值
const props = defineProps({
type: {
default: 'edit',
type: String,
},
});
二、子传父— defineEmits
父组件: 拿到子组件传过来的数据false给handleVisible方法里
<el-dialog :close-on-click-modal="false" :title="dialog.title" v-model="dialog.visible" width="1000px" top="15px"
@close="cancel">
<form-children type="create" @changeVisible="handleVisible" ref="formChildrenRef"/>
</el-dialog>
function handleVisible(data:any) {
state.dialog.visible = data
}
子组件: 子组件中通过emit调用父组件中的changeVisible方法,给父组件的这个方法里传入数据false
if (state.type == 'create') {
addScene(state.formData).then(() => {
ElMessage.success(state.type == 'edit' ? t('message.modifySuccess') : t('message.addSuccess'));
emit('changeVisible', false)
cancel();
});
}
三、子组件暴露属性给父组件 defineExpose (父组件调用子组件的方法)
当父组件想直接使用子组件的属性或者方法时,子组件可以使用defineExpose暴露自身的属性或者方法。
父组件: 父组件通过ref定义子组件实例,通过调用实例获得子组件的属性和方法
<el-dialog :close-on-click-modal="false" :title="dialog.title" v-model="dialog.visible" width="1000px" top="15px"
@close="cancel">
<form-children type="create" @changeVisible="handleVisible" ref="formChildrenRef"/>
</el-dialog>
//拿到子组件实例
const formChildrenRef = ref()
function cancel() {
resetForm();
state.dialog.visible = false;
// 调用子组件的方法
if(formChildrenRef.value) {
formChildrenRef.value.resetForm()
}
}
子组件: 子组件通过defineExpose暴露对象和方法
function resetForm() {
state.actions = []
state.conditions = []
state.actionTags = []
state.conditionsTags = []
state.formData = {
sceneName: '',
sceneType: 1,
identifierType: null,
enable: 1,
}
dataFormRef.value.resetFields();
i18nFormRef.value.formRef.resetFields();
}
defineExpose({
resetForm
})
四、依赖注入Provide / Inject
在父子组件传递数据时,通常使用的是 props 和 emit,父传子时,使用的是 props,如果是父组件传孙组件时,就需要先传给子组件,子组件再传给孙组件,如果多个子组件或多个孙组件使用时,就需要传很多次,会很麻烦。
像这种情况,可以使用 provide 和 inject 解决这种问题,不论组件嵌套多深,父组件都可以为所有子组件或孙组件提供数据,父组件使用 provide 提供数据,子组件或孙组件 inject 注入数据。同时兄弟组件之间传值更方便。
如下为父组件Root.vue:
<template>
<div>
我是root组件
<Footer></Footer>
</div>
</template>
<script setup lang="ts">
import { provide, ref } from 'vue'
import Footer from './Footer.vue'
const toChildValue= ref<string>("我是给所有子组件的值")
// 将toChildValue注入到所有子组件中
provide(/* 注入名 */ 'toChildValue', /* 值 */ toChildValue)
</script>
如下为子组件Footer.vue:
<template>
<div>
我是footer组件
<div>
接收父组件的值:{{getFatherValue}}
</div>
<DeepChild></DeepChild>
</div>
</template>
<script setup lang="ts">
import DeepChild from "./DeepChild.vue"
import {ref,inject,Ref} from "vue";
// 获取父组件提供的值
// 如果没有祖先组件提供 "toChildValue"
// ref("") 会是 "这是默认值"
const getFatherValue = inject<Ref<string>>(/* 注入名 */"toChildValue",/* 默认值 */ ref(""))
</script>
如下为孙子组件DeepChild.vue:
<template>
<div>
我是deepChild组件
<div>
接收爷爷组件的值:{{getGrandFatherValue}}
</div>
</div>
</template>
<script setup lang="ts">
import {inject, ref, Ref} from "vue";
// 获取爷爷组件提供的值
// 如果没有爷爷组件提供 "toChildValue"
// value 会是 ""
const getGrandFatherValue = inject<Ref<string>>(/* 注入名 */"toChildValue",/* 默认值 */ ref(""))
</script>
当最顶层的组件Root.vue传值给所有子组件时,使用provide进行注入
provide(/* 注入名 */ 'toChildValue', /* 值 */ toChildValue)
而后无论哪个子组件想要获取toChildValue的值,只需使用inject即可
inject<Ref<string>>(/* 注入名 */"toChildValue",/* 默认值 */ ref(""))
为什么父子组件传值时有时用props不行,用provide可以?
- 父组件通过props向子组件传递数据时,只能实现单向的数据流动,也就是说只能从父组件传递数据到子组件,而子组件无法直接修改父组件的数据。
- 而provide和inject是Vue提供的一种更加灵活的数据传递方式,可以实现从祖先组件向后代组件的跨层级传递数据,而且不受单向数据流的限制,后代组件可以直接修改祖先组件的数据。
- 这种方式更加适合非父子关系的组件通信,例如兄弟组件之间共享数据等。因此,使用provide和inject可以更加方便地实现组件之间的数据传递。
更多推荐
所有评论(0)