Search code examples
vue.jsvuejs3vue-composition-api

Vue 3 how to get information about $children


This my old code with VUE 2 in Tabs component:

created() {
   this.tabs = this.$children;
}

Tabs:

<Tabs> 
  <Tab title="tab title">
    ....
  </Tab>
  <Tab title="tab title">
    ....
  </Tab> 
</Tabs>

VUE 3: How can I get some information about childrens in Tabs component, using composition API? Get length, iterate over them, and create tabs header, ...etc? Any ideas? (using composition API)


Solution

  • This is my Vue 3 component now. I used provide to get information in child Tab component.

    <template>
      <div class="tabs">
        <div class="tabs-header">
          <div
            v-for="(tab, index) in tabs"
            :key="index"
            @click="selectTab(index)"
            :class="{'tab-selected': index === selectedIndex}"
            class="tab"
          >
            {{ tab.props.title }}
          </div>
        </div>
        <slot></slot>
      </div>
    </template>
    
    <script lang="ts">
    import {defineComponent, reactive, provide, onMounted, onBeforeMount, toRefs, VNode} from "vue";
        
    interface TabProps {
      title: string;
    }
        
    export default defineComponent({
      name: "Tabs",
      setup(_, {slots}) {
        const state = reactive({
          selectedIndex: 0,
          tabs: [] as VNode<TabProps>[],
          count: 0
        });
        
        provide("TabsProvider", state);
        
        const selectTab = (i: number) => {
          state.selectedIndex = i;
        };
        
        onBeforeMount(() => {
          if (slots.default) {
            state.tabs = slots.default().filter((child) => child.type.name === "Tab");
          }
        });
    
        onMounted(() => {
          selectTab(0);
        });
    
        return {...toRefs(state), selectTab};
      }
    });
    </script>
    

    Tab component:

    <script lang="ts">
    export default defineComponent({
      name: "Tab",
      setup() {
        const index = ref(0);
        const isActive = ref(false);
    
        const tabs = inject("TabsProvider");
    
        watch(
          () => tabs.selectedIndex,
          () => {
            isActive.value = index.value === tabs.selectedIndex;
          }
        );
    
        onBeforeMount(() => {
          index.value = tabs.count;
          tabs.count++;
          isActive.value = index.value === tabs.selectedIndex;
        });
        return {index, isActive};
      }
    });
    </script>
    
    <template>
      <div class="tab" v-show="isActive">
          <slot></slot>
      </div>
    </template>