vue3没了$children,如何获取子组件???

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容