父子组件之间的通讯
父传子 defineProps
父组件传值给子组件主要是由父组件为子组件通过v-bind绑定数值,而后传给子组件;子组件则通过 defineProps 接收使用。
<template>
<p>这是父组件</p>
<!-- 子组件 -->
<ChildrenCom :name="name" :setCount="setCount"/>
<el-button @click="setCount">父组件传递过来的方法</el-button>
</template>
<script>
import { ChildrenCom } from './ChildrenCom';
import { ref } from 'vue'
const name = ref('父传子state')
</script>
<template>
<p>这是子组件</p>
<span>传递过来的值{{ name }} </span>
</template>
<script>
import { ref } from 'vue'
/**
* 子组件获取参数方式
* 1、defineProps(['count']);
* 2、defineProps({count:number);
* 3、defineProps({count:{type:number,default:0}});
*/
const props = defineProps({
name: String,
setCount: Function,
});
console.log(props.name)
</script>
父组件传递子组件方法还是state基本一样
子传父
1、defineProps方式
比较贴合React
<script setup>
import ChildrenCom from '@/components/DemoCon.vue';
import { ref } from 'vue';
const count = ref();
const transmitFather = params => {
count.value = params;
};
</script>
<template>
父组件
<p>这是子组件传递过来的值:{{ count }}</p>
<!-- 子组件 -->
<ChildrenCom :transmitFather="transmitFather" />
</template>
<script setup>
import { ref } from 'vue';
const count = ref('子组件传递的值');
const props = defineProps(['transmitFather']);
const transmit = () => {
props.transmitFather(count.value);
};
</script>
<template>
<p>这是子组件</p>
<el-button @click="transmit">子传父方法</el-button>
</template>
2、defineEmits方式
子组件传值给父组件主要是子组件通过defineEmits注册一个自定义事件,而后触发emit去调用该自定义事件,并传递参数给父组件。
在父组件中调用子组件时,通过v-on绑定一个函数,通过该函数获取传过来的值。
<script setup>
import ChildrenCom from '@/components/DemoCon.vue';
import { ref } from 'vue';
const count = ref();
const transmitFather = params => {
count.value = params;
};
</script>
<template>
父组件
<p>这是子组件传递过来的值:{{ count }}</p>
<!-- 子组件 -->
<ChildrenCom @transmit-father="transmitFather" />
</template>
<template>
<p>这是子组件</p>
<el-button @click="transmit">子传父方法</el-button>
</template>
<script setup>
import { ref, defineEmits } from 'vue';
const count = ref('子组件传递的值');
const emit = defineEmits(['transmit-father']);
const transmit = () => {
emit('transmit-father', count.value);
};
</script>
父组件调用子组件 defineExpose
默认情况下在 <script setup>语法糖下组件内部的属性和方法是不开放给父组件访问的,可以通过 defineExpose编译指定哪些属性和方法允许访问,父组件中使用ref.value调用子组件暴露的属性或方法。
在组件挂在完璧之后调用 也就是 onMethods 生命周期
<template>
<div>我是父组件</div>
<el-button @click="getSonMethod">获取子组件的方法</el-button>
<ChildrenCom ref="sonMethodsRef"/>
</template>
<script setup>
import { ChildrenCom } from './ChildrenCom';
import { ref } from "vue";
const sonMethodsRef = ref()
const getSonMethod = () => {
sonMethodsRef.value.toFatherMethod()
console.log(sonMethodsRef.value.toFatherValue)
}
</script>
<template>
<div>我是子组件</div>
</template>
<script setup>
import { defineExpose } from "vue";
const toFatherMethod = () => {
console.log("我是要暴露给父组件的方法")
}
// 暴露给父组件的值
const toFatherValue = ref<string>("我是要暴露给父组件的值")
// 暴露方法和属性给父组件
defineExpose({toFatherMethod, toFatherValue})
</script>
在子组件中定义属性toFatherValue和方法toFatherMethod,而后通过defineExpose暴露出来。
父组件调用时,为子组件绑定一个ref,并定义一个ref变量sonMethodRef,通过调用sonMethodRef,来获取子组件暴露出来的属性和方法。
多层级嵌套传递 provide 和 inject
嵌套层级关系 : Father => SecondChild 组件传递参数,并在SecondChild组件里可以进行修改father组件
Father > FirstChild > SecondChild
<template>
<p>你好,这是最上层组件</p>
<FirstChild />
</template>
<script setup>
import { provide, ref } from 'vue';
import FirstChild from './FirstChild.vue';
const state = ref(0);
const setState = e => {
console.log(e);
state.value++;
};
provide('father-data', { state, name: 'Tom' });
provide('father-fun', setState);
</script>
<template>
<SecondChild />
</template>
<script setup>
import SecondChild from '../components/SecondChild.vue';
</script>
<template>
父组件传过来的值:{{ state }}--{{name}}
<el-button @click="setState('ccc')">切换父组件的值</el-button>
</template>
<script setup>
import { inject } from 'vue';
const {state,name} = inject('father-data');
const setState = inject('father-fun');
</script>
父子组件双向绑定
<template>
<el-button @click="dialog2Visible = true">组件内需要状态, 有自定义关闭按钮</el-button>
<dialog-2 v-if="dialog2Visible" v-model="dialog2Visible" v-model:countAdd="count"></dialog-2>
</template>
<script setup>
import { ref } from 'vue';
import Dialog2 from './Dialog2.vue';
const count = ref(100);
const dialog2Visible = ref(false);
</script>
// Dialog2 组件
<template>
<el-dialog
:model-value="modelValue"
title="Tips"
width="500"
@close="hide"
>
<span>组件内部使用visible数据源 {{countAdd}}</span>
<el-button @click="changeVmodal">Cancel</el-button>
<div @click="$emit('update:modelValue', '喷射河马')">{{modelValue}}</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="hide">Cancel</el-button>
<el-button type="primary" @click="hide">Confirm</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import {ref} from 'vue'
const props = defineProps({
modelValue: Boolean, // 接收父组件使用 v-model 传进来的值,必须用 modelValue 这个名字来接收
countAdd:Number
});
const count = ref(0)
const emit = defineEmits([
'update:modelValue', // 必须用 update:modelValue 这个名字来通知父组件修改值
'update:countAdd'
]);
const changeVmodal =()=>{
emit('update:countAdd', count.value++ )
}
function hide() {emit('update:modelValue', false)}
</script>