2

I am having difficulty to make use of named slot from children in parent component. So I am making tabs component with main Tabs and child Tab components. My Tabs:

<template>
    <div class="tabsMainContainer">
        <div class="tabsContainer">
            <ul class="tabsHeader">
                <li
                    v-for="(tab, index) in tabs"
                    :key="tab.title"
                    :class="{tabActive: (index == selectedIndex)}"
                    @click="selectTab(index)"
                >
                <slot name="icon"/>
                    {{ tab.title }}
                </li>
            </ul>
        </div>
        <div class="tabsContent"><slot/></div>
    </div>
</template>

I get tabs object with this.$children

and then my Tab component:

<template>
  <div v-show="isActive" class="tab">
      <slot name="icon"/>
    <slot/>
  </div>
</template>

And use of that:

<Tabs class="tabsComponent">
        <Tab title="first">
            <template v-slot:icon>Icon</template>
            Content
        </Tab>
        <Tab title="second">Content second</Tab>
</Tabs >

while Content as such works fine, it appears in default slot, the icon slot also appears in default slot in main Tab component. How can I get icon slot from children, and display it in icon slot of main Tab component?

uneasy
  • 547
  • 1
  • 7
  • 17

3 Answers3

0

I also had a same kind of requirement. What I did was adding slot inside the main component's slot with the same name

In your Tab component

<template>
  <div v-show="isActive" class="tab">
    <template v-slot:icon>
      <slot name="icon" />
    </template>
  </div>
</template>
pradeep
  • 550
  • 4
  • 10
0

First of all, I use google translate. Sorry, I may have spelled it wrong.

https://stackoverflow.com/a/64568036

I got an example from @ingrid-oberbüchler.

My solution

Layout.vue

<Tabs class="tabsComponent">
  <Tab title="first">
     <template v-slot:icon>Icon</template>
       Content
  </Tab>
  <Tab title="second">Content second</Tab>
</Tabs>

Tabs.vue

<template>
  <div class="title">
     {{ tabsProvider.tabs[tabsProvider.selectedIndex].props.title }}
  </div>
  <div class="content">
    <slot/>
  </div>
 
  <div class="icon">
    <component :is="tabsProvider.tabs[tabsProvider.selectedIndex].children.icon"/>
  </div>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
  data() {
    return {
      tabsProvider: {
        selectedIndex: 0,
        tabs: [],
        count: 0,
      },
    };
  },
  provide() {
    return {
      $tabsProvider: this.tabsProvider,
    };
  },
  created() {
    this.tabsProvider.tabs = this.$slots.default().filter((child) => child.type.name === "Tab");
  },
}
</script>

Tab.vue

<template>
  <div v-show="isActive">
    <slot />
  </div>
</template>



<script>
import { defineComponent } from "vue";

export default defineComponent({
  name: "Tab",
  props: {
    title: {
      type: String,
    },
  },
  inject: ["$tabsProvider"],
  data() {
    return {
      index: 0,
      isActive: false,
    };
  },
  beforeMount() {
    this.index = this.$tabsProvider.count;
    this.$tabsProvider.count++;
    this.isActive = this.index === this.$tabsProvider.selectedIndex;
  },
  watch: {
    "$tabsProvider.selectedIndex": {
      handler(val, oldVal) {
        this.isActive = this.index === this.$tabsProvider.selectedIndex;
      },
      deep: true,
    },
  },
});
</script>

-1

Simplest example

let's admit x component is parent

<div class="x">x component</div>

let's admit y component is child

<div class="y">y component</div>

How to be process?

<Ycomponent>
   <slot name="example1"/>
   <slot name="example2"/>
   <slot name="example3"/>
</Ycomponent>

<Xcomponent>
   <Ycomponent>
        <button slot="example1">button</button>
        <span slot="example2">Span</span>
        <img slot="example3" src="/"/>
   </Ycomponent>
</Xcomponent>

I hope I could help.

Taner Akhan
  • 138
  • 1
  • 7
  • That's not quiet what I meant. So in your example, I want Y component slots, to be in X component slots with same names. But that does not seem possible. But maybe as an alternative, can I access this.$children.slot and render it on parent component maybe ? – uneasy Nov 13 '20 at 11:29
  • i don't understand, you can using online editor? (like CodeSandbox, codepen, jsfiddle) – Taner Akhan Nov 13 '20 at 11:52
  • CodeSandbox won't make more sense than the code I pasted, as I don't know how to make it work. but looks like it won't work the way I want. I know how to use named slots the way you showed it. but just add same to X component, and I want it to be from Y component but in X component – uneasy Nov 13 '20 at 12:05
  • I guess you are looking for something like here https://codepen.io/tatimblin/pen/oWKdjR – Taner Akhan Nov 13 '20 at 12:23
  • No, that's what I already have, but I want to add Icon component to the tab name, so like adding to your example ` ` – uneasy Nov 13 '20 at 13:47