美文网首页vue3vue
vue3没了$children,如何获取子组件???

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

作者: 踏莎行 | 来源:发表于2021-10-24 10:35 被阅读0次

    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

    相关文章

      网友评论

        本文标题:vue3没了$children,如何获取子组件???

        本文链接:https://www.haomeiwen.com/subject/mvrxaltx.html