简体   繁体   中英

VueJs - pass slot from child component to parent

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?

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>

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>

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM