vue3已經(jīng)推出很久了,相信大家也都體驗(yàn)過了荔泳,變化很大蕉饼,尤其是composition Api的出現(xiàn),而且對typescript的支持更好了玛歌,但是寫慣了vue2的我昧港,在使用setup的時候,碰到了一個問題:setup里面沒有this支子,而且廢除了$children创肥,那么我要如何獲取當(dāng)前組件的實(shí)例和獲取當(dāng)前組件的子組件?值朋?
本文創(chuàng)建兩個演示示例組件:Parent.vue叹侄、Children,vue
一、獲取當(dāng)前組件
vue3提供了一個getCurrentInstance方法用來獲取當(dāng)前組件的實(shí)例
<template>
<div class="parent">
{{ msg }}
</div>
</template>
<script lang="ts">
import { defineComponent, getCurrentInstance } from "vue";
export default defineComponent({
setup() {
const instance = getCurrentInstance();
console.log(instance);
let msg = "我是父組件";
return { msg };
},
});
</script>
<style scoped>
.parent {
color: rgb(233, 35, 0);
position: relative;
font-size: 30px;
}
</style>
來看頁面
控制臺中打印出的對象就是當(dāng)前組件的實(shí)例昨登,拿到這個實(shí)例對象之后就能調(diào)用里面的方法趾代,比如parent,props等數(shù)據(jù)丰辣,這個就是一個方法的事兒
一撒强、獲取當(dāng)前組件的子組件實(shí)例
先來看看vue3官網(wǎng)對$children的說明
在 3.x 中,
$children
property 已被移除笙什,且不再支持飘哨。如果你需要訪問子組件實(shí)例,我們建議使用 $refs琐凭。
意思就是說推薦我們使用ref對子組件進(jìn)行綁定芽隆,然后訪問子組件
在Children.vue中家點(diǎn)東西
// Children.vue
<template>
<div class="children">
<h2>我是子組件</h2>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup() {
return {};
},
});
</script>
父組件注冊Children
<template>
<div class="parent">
<Children></Children>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import Children from "./Children.vue";
export default defineComponent({
components: {
Children,
},
setup() {
return {};
},
});
</script>
然后就能看到子組件的內(nèi)容了
下面就通過ref來綁定子組件,要在vue中引入ref淘正。需要注意的是setup的執(zhí)行是早于mounted摆马,甚至早于created生命周期的,所以通過ref綁定成功之后需要在mounted生命周期才能訪問到你綁定的子組件的
<template>
<div class="parent">
<Children ref="childrenRef"></Children>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, ref } from "vue";
import Children from "./Children.vue";
export default defineComponent({
components: {
Children,
},
setup() {
const childrenRef = ref(null);
onMounted(() => {
console.log(childrenRef);
console.log(childrenRef.value);
});
return { childrenRef };
},
});
</script>
調(diào)用子組件的方法
setup的第二個參數(shù)上有一個expose 屬性鸿吆,這是vue3.2+才出現(xiàn)的內(nèi)容囤采,通過expose 可以將該組件內(nèi)部的一些方法等對外進(jìn)行暴露
<template>
<div class="children">
<h2>我是子組件</h2>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
setup(props, { expose }) {
let counter = ref(0);
const setCounter = (count: number) => {
counter.value = count;
};
expose({
setCounter,
});
return { counter };
},
});
</script>
然后父組件通過ref綁定子組件之后,就可以調(diào)用子組件暴露出來的setCounter函數(shù)了
<template>
<div class="parent">
<Children ref="childrenRef"></Children>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, ref } from "vue";
import Children from "./Children.vue";
export default defineComponent({
components: {
Children,
},
setup() {
const childrenRef = ref(null);
onMounted(() => {
childrenRef.value.setCounter(2);
});
return { childrenRef };
},
});
</script>
再來看一個例子
假如有這么一個需求惩淳,需要你將Children以插槽的方式傳進(jìn)Parent組件蕉毯,
<template>
<div class="parent">
<slot></slot>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup() {
return {};
},
});
</script>
并且Parent組件內(nèi)部要對插槽的內(nèi)容進(jìn)行校驗(yàn)乓搬,必須是Children組件。再創(chuàng)建一個test.vue
// test.vue
<template>
<div>
<Parent>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
</Parent>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import Parent from "./components/Parent.vue";
import Children from "./components/Children.vue";
export default defineComponent({
components: {
Parent,
Children,
},
setup() {
return {};
},
});
</script>
需求的意思就是Parent組件內(nèi)部要進(jìn)行校驗(yàn)代虾,總不可能將Parent內(nèi)部的直接子元素一一綁定ref吧进肯?這樣太過冗余,如果傳入了上百個Children組件呢棉磨?更麻煩了江掩。
所以還是要來說說setup的參數(shù)了,setup第二個參數(shù)context上有一個屬性slots,slots上又有一個方法default乘瓤,該方法的返回值就是一個插槽內(nèi)容的數(shù)組
<template>
<div class="parent">
<slot></slot>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup(props, context) {
console.log(context);
const defaults = context.slots.default()
console.log(defaults);
return {};
},
});
</script>
接下來在Parent.vue中導(dǎo)入Children組件环形,并在test.vue的Parent組件中添加一個div
<Parent>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<Children></Children>
<div>我是div</div>
</Parent>
然后Parent組件內(nèi)部進(jìn)行判斷
<template>
<div class="parent">
<slot></slot>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import Children from "./Children.vue";
export default defineComponent({
setup(props, context) {
const defaults = context.slots.default();
defaults.forEach((item) => {
console.log(item.type === Children);
});
return {};
},
});
</script>