vue3已经推出很久了,相信大家也都体验过了,变化很大,尤其是composition Api的出现,而且对typescript的支持更好了,但是写惯了vue2的我,在使用setup的时候,碰到了一个问题:setup里面没有this,而且废除了$children,那么我要如何获取当前组件的实例和获取当前组件的子组件??
本文创建两个演示示例组件:Parent.vue、Children,vue
一、获取当前组件
vue3提供了一个getCurrentInstance方法用来获取当前组件的实例
<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>
来看页面
instance.png
控制台中打印出的对象就是当前组件的实例,拿到这个实例对象之后就能调用里面的方法,比如parent,props等数据,这个就是一个方法的事儿
一、获取当前组件的子组件实例
先来看看vue3官网对$children的说明
在 3.x 中,
$children
property 已被移除,且不再支持。如果你需要访问子组件实例,我们建议使用 $refs。
意思就是说推荐我们使用ref对子组件进行绑定,然后访问子组件
在Children.vue中家点东西
// 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>
然后就能看到子组件的内容了
view.png
下面就通过ref来绑定子组件,要在vue中引入ref。需要注意的是setup的执行是早于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>
chidren.png
调用子组件的方法
setup的第二个参数上有一个expose 属性,这是vue3.2+才出现的内容,通过expose 可以将该组件内部的一些方法等对外进行暴露
<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绑定子组件之后,就可以调用子组件暴露出来的setCounter函数了
<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以插槽的方式传进Parent组件,
<template>
<div class="parent">
<slot></slot>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup() {
return {};
},
});
</script>
并且Parent组件内部要对插槽的内容进行校验,必须是Children组件。再创建一个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组件内部要进行校验,总不可能将Parent内部的直接子元素一一绑定ref吧?这样太过冗余,如果传入了上百个Children组件呢?更麻烦了。
所以还是要来说说setup的参数了,setup第二个参数context上有一个属性slots,slots上又有一个方法default,该方法的返回值就是一个插槽内容的数组
<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>
info.png
Snipaste_2021-10-24_10-04-41.png
接下来在Parent.vue中导入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组件内部进行判断
<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>
Snipaste_2021-10-24_10-10-53.png
网友评论