【问题标题】:Vuejs nested slots: how to pass slot to grandchildVuejs嵌套插槽:如何将插槽传递给孙子
【发布时间】:2019-04-25 02:58:56
【问题描述】:

我使用不同的 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>

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

例子:

// 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>

&lt;slot slot="activator"&gt; 是一个不正确的等式。目标是从父级(即示例中的&lt;button&gt;..&lt;/button&gt;)拉取内容,并将其用作v-menu 中的slot="activator"

我可以这样写:

<v-menu>
  <a slot="activator"><slot/></a>
  ...
</v-menu>

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

<div class="v-menu__activator">
  <a>
    <button>My special menu trigger</button>
  </a>
</div>

这不是我想要的。是否可以在这里摆脱 &lt;a&gt; 包装器?

更新: 我们可以使用像&lt;template slot="activator"&gt;&lt;slot name="activator"/&gt;&lt;/template&gt; 这样的结构来给孙子扔一些槽。但是,如果我们有多个插槽并且想要全部代理它们怎么办?这就像插槽的 inheritAttrs 和 v-bind="$attrs"。目前可以吗?

例如,vuetify 中有 &lt;v-autocomplete&gt; 组件,它有 append、prepend、label、no-data、progress、item、selection 等槽。我围绕它写了一些包装器组件,它目前看起来像:

<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>

这里可以避免所有槽枚举吗?

【问题讨论】:

  • 属性 name 而不是 slot 所以:&lt;slot name="activator"&gt;

标签: vue.js vuejs2 vuetify.js


【解决方案1】:

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

// App.vue
<template>
  <div id="app">
    <test>
      <template slot="activator">
        Click <b>me</b>!
      </template>
    </test>
  </div>
</template>
// Test.vue
<template>
  <div class="wrapper">
    <grand-child>
      <template slot="activator">
        <slot name="activator"></slot>
      </template>
    </grand-child>

    This is some text
  </div>
</template>
// 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>

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

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

为了完整起见,作用域插槽可以通过$scopedSlots 访问并像这样传播:

<grand-child>
  <template v-for="(_, slot) in $scopedSlots" v-slot:[slot]="props">
    <slot :name="slot" v-bind="props" />
  </template>
</grand-child>

sourcecomment

【讨论】:

  • 谢谢,&lt;template slot="activator"&gt;&lt;slot name="activator"/&gt;&lt;/template&gt; 构造工作正常。你认为有可能继承所有的槽吗(比如我们有 inheritAttrs 和使用 v-bind="$attrs" 的可能性)?我更新了问题。
  • 谢谢这是准确的。作用域插槽呢?
  • &lt;template v-for="(_, slot) of $scopedSlots" v-slot:[slot]="props"&gt;&lt;slot :name="slot" v-bind="props"/&gt;&lt;/template&gt; 无耻地从stackoverflow.com/questions/50891858/…盗取
  • 为了完整起见,我已将其添加到带有来源的答案中。 @EmmanuelMahuni
  • 根据我想要实现的目标,使用 $scopedSlots 的示例对我有用。谢谢
猜你喜欢
  • 2020-03-12
  • 2018-08-19
  • 1970-01-01
  • 1970-01-01
  • 2017-12-06
  • 1970-01-01
  • 1970-01-01
  • 2018-11-11
  • 2019-06-08
相关资源
最近更新 更多