Vuejs嵌套插槽:如何将插槽传递给孙子

Kas*_*tin 2 vue.js vuejs2 vuetify.js

我使用不同的vuetify组件,例如v-menu.它有一个这样的模板:

<v-menu>
  <a slot="activator">menu</a>
  <v-list>
    <v-list-tile>Menu Entry 1</v-list-tile>
    <v-list-tile>Menu Entry 2</v-list-tile>
  </v-list>
</v-menu>
Run Code Online (Sandbox Code Playgroud)

假设我想在它周围添加另一个包装器.这是我的特殊菜单组件,它有一些预定义的菜单选项.我希望它也有一个激活器插槽.最后应该以某种方式分配给原始的v菜单激活器插槽.可能吗?

例:

// index.vue: 
<template>
  <my-special-menu>
    <button>My special menu trigger</button>
  </my-special-menu>
</template>

// MySpecialMenu.vue
<template>
  <v-menu>
    <slot slot="activator"/> <-- I don't know how to write this line
    <v-list>...</v-list>
  </v-menu>
</template>
Run Code Online (Sandbox Code Playgroud)

<slot slot="activator">是一个不正确的等式.目标是从父项(<button>..</button>在示例中)中提取内容,并slot="activator"在v-menu中使用它.

我可以这样写:

<v-menu>
  <a slot="activator"><slot/></a>
  ...
</v-menu>
Run Code Online (Sandbox Code Playgroud)

但是这种情况下结果模板将是:

<div class="v-menu__activator">
  <a>
    <button>My special menu trigger</button>
  </a>
</div>
Run Code Online (Sandbox Code Playgroud)

这不完全是我想要的.有可能在<a>这里摆脱包装吗?

更新:我们可以使用一种建筑,就像<template slot="activator"><slot name="activator"/></template>给一个大孩子扔一些槽.但是,如果我们有多个插槽并且我们想要将它们全部代理呢?这就像继承蚂蚁和v-bind="$attrs"插槽.目前有可能吗?

例如,<v-autocomplete>vuetify中的组件具有追加,前置,标签,无数据,进度,项目,选择等插槽.我在这周围写了一些包装器组件,它目前看起来像:

<template>
  <v-autocomplete ..>
    <template slot="append"><slot name="append"/></template>
    <template slot="prepend"><slot name="prepend"/></template>
    <template slot="label"><slot name="label"/></template>
    ...
    <template slot="item" slot-scope="props"><slot name="item" v-bind="props"/></template>
  </v-autocomplete>
</template>
Run Code Online (Sandbox Code Playgroud)

是否可以避免所有插槽枚举?

Vic*_*sov 19

如果您同时拥有带有 props 的命名和未命名插槽:

视图3

<template v-for="(_, name) in $slots" #[name]="slotData">
  <slot :name="name" v-bind="slotData || {}" />
</template>
Run Code Online (Sandbox Code Playgroud)

打字稿版本

<template v-for="(_, name) in ($slots as {})" #[name]="slotData">
  <slot :name="name" v-bind="slotData || {}" />
</template>
Run Code Online (Sandbox Code Playgroud)


Tin*_*ger 13

由于折旧:slot$scopedSlots属性,我遇到了 EsLint 错误。

所以我将 @Sumurai8 的两个答案结合起来,效果很好:

<template v-for="(_, slot) in $slots" v-slot:[slot]>
  <slot :name="slot"></slot>
</template>
Run Code Online (Sandbox Code Playgroud)


Sum*_*ai8 12

如果将该slot属性放在html元素上,则该html元素将传递给子组件以使用该名称填充插槽.如果您不想传递html元素,则可以在组件中slottemplate标记上使用.模板标签对元素进行分组,但不会渲染为html元素,这在这里是完美的.您也可以将模板标签用于其他内容,例如,将v-if中的元素分组,或者使用v-for重复多个元素.

// App.vue
<template>
  <div id="app">
    <test>
      <template slot="activator">
        Click <b>me</b>!
      </template>
    </test>
  </div>
</template>
Run Code Online (Sandbox Code Playgroud)
// Test.vue
<template>
  <div class="wrapper">
    <grand-child>
      <template slot="activator">
        <slot name="activator"></slot>
      </template>
    </grand-child>

    This is some text
  </div>
</template>
Run Code Online (Sandbox Code Playgroud)
// GrandChild.vue
<template>
  <div>
    <a href="#" @click="toggle = !toggle">
      <slot name="activator">Default</slot>
    </a>

    <div v-if="toggle">This appears and disappears</div>
  </div>
</template>
Run Code Online (Sandbox Code Playgroud)

编辑Vue模板

编辑:如果你想为任意插槽执行此操作,这也是可能的.this.$slots包含插槽及其内容,因此使用以下内容,您可以将插槽内容传递到具有相同名称的插槽:

<grand-child>
  <template v-for="(_, slot) in $slots">
    <template :slot="slot">
      <slot :name="slot"></slot>
    </template>
  </template>
</grand-child>
Run Code Online (Sandbox Code Playgroud)

编辑Vue模板