【问题标题】:Passing slot into slot in Vue.js将插槽传递到 Vue.js 中的插槽
【发布时间】:2020-06-05 22:15:48
【问题描述】:

我正在尝试将 slot 传递到 slot 中,但是需要向下传递 slot 的子组件看不到它。

在子 (TheTable) 中,我有来自 Core UI for Vue (CDataTable) 的表格组件,它需要我想从父级传递的某些插槽:

  <CDataTable
      class="overflow-auto"
      :items="this.items"
      :fields="fieldData"
      :sorter="{ external: true, resetable: true }"
      :sorter-value="this.sorterValue"
      :table-filter="{ external: true, lazy: false, placeholder: 'Enter here', label: 'Search:'}"
      :responsive="false"
      :loading="this.loading"
      :hover="true"
      :items-per-page-select="true"
      :items-per-page="this.perPage"
      @pagination-change="paginationChanged"
      @update:sorter-value="sorterUpdated"
      @update:table-filter-value="filterUpdated"
  >
      <slot name="requiredTableFields"></slot>
  </CDataTable>

在我的父组件中:

<TheTable
        v-bind:fields="fields"
        v-bind:endpoint-url="endpointUrl"
>
    <template slot="requiredTableFields">
        <td slot="name" slot-scope="{item}">
            <div>{{ item['attributes.email'] }}</div>
            <div class="small text-muted">
                {{ item['attributes.firstname'] }} {{ item['attributes.lastname'] }}
            </div>
        </td>
        <td slot="registered" slot-scope="{item}">
            <template v-if="item['attributes.created_at']">{{ item['attributes.created_at'] }}</template>
            <template v-else>Not setup yet</template>
        </td>
    </template>
</TheTable>

有什么办法让它工作吗? 干杯, 卡斯珀

【问题讨论】:

  • vue 2.6 有一个新的waytemplate v-slot:requiredTableFields
  • 遗憾的是没有运气,问题似乎在于桌子没有看到它的插槽......
  • CDataTable 需要为其插槽提供模板。您需要先设置预期的模板。我认为您正在尝试从父组件传递此模板对吗?。
  • 是的,我正在尝试从父母那里传递它们。实际上无法在那里设置这些模板,因为它们会有所不同,带有 CDataTable 的组件将用于抽象。
  • 我不认为这是可能的,但您可以尝试使用以下库 github.com/LinusBorg/portal-vue

标签: html vue.js core-ui


【解决方案1】:

将基础插槽合并到单个 requiredTableFields 插槽中是行不通的,因为一旦子插槽被合并,就没有(简单的)方法可以将它们分开。

相反,您可以将插槽分开:

<TheTable ...>
  <template v-slot:name="{ item }">
    <td>
      ...
    </td>
  </template >
  <template v-slot:registered="{ item }">
    <td>
      ...
    </td>
  </template>
</TheTable>

这会将两个作用域插槽 nameregistered 传递到 TheTable

假设您不想将插槽名称硬编码为 TheTable,那么您需要遍历 $scopedSlots 以动态包含它们。

<CDataTable ...>
  <template v-for="(x, slotName) in $scopedSlots" v-slot:[slotName]="context">
    <slot :name="slotName" v-bind="context" />
  </template>
</CDataTable>

对此的一些说明:

  1. x 没有被使用,我们只需要遍历插槽名称。
  2. 与作用域槽关联的“数据”称为context,只是被传递。
  3. 如果插槽不是作用域插槽,它会略有不同。我们将迭代 $slots 并删除所有引用 context 的部分。
  4. :name 属性的开头有一个:,因为我们要传递一个动态名称。不幸的是,原始问题中的一个位置也称为name,这可能会导致一些混乱。
  5. v-bind="context" 部分类似于 JavaScript 扩展运算符,如果这样更清楚的话。把它想象成attributes = { name: slotName, ...context }

下面是一个完整的示例,说明了上述技术。它没有使用CDataTable,但传递slots的核心原理是完全一样的。

const Comp2 = {
  template: `
    <div>
      <h4>Left</h4>
      <div><slot name="top" item="Red" /></div>
      <h4>Right</h4>
      <div><slot name="bottom" item="Green" /></div>
    </div>
  `
}

const Comp1 = {
  template: `
    <div>
      <comp2>
        <template v-for="(x, slotName) in $scopedSlots" v-slot:[slotName]="context">
          <slot :name="slotName" v-bind="context" />
        </template>
      </comp2>
    </div>
  `,
  
  components: {
    Comp2
  }
}

new Vue({
  el: '#app',

  components: {
    Comp1
  }
})
<script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>

<div id="app">
  <comp1>
    <template v-slot:top="{ item }">
      <button>Slot 1 - {{ item }}</button>
    </template>
    <template v-slot:bottom="{ item }">
      <button>Slot 2 - {{ item }}</button>
    </template>
  </comp1>
</div>

【讨论】:

    猜你喜欢
    • 2020-03-12
    • 2020-11-13
    • 1970-01-01
    • 2017-07-13
    • 1970-01-01
    • 2019-04-25
    • 2021-04-03
    • 2017-06-26
    • 2011-07-06
    相关资源
    最近更新 更多