如何在Vue中使用重复的命名插槽

时间:2018-09-28 09:22:25

标签: vue.js vuejs2 vue-component vuetify.js

我正在Vuetify中为v-stepper包装的组件。在这种情况下,我希望用户在使用组件时定义一个插槽,然后我将使用该插槽名称来构建步骤。

我需要在桌面视图和移动视图中都存在该插槽。我尝试使用v-if隐藏是否可移动,但这导致了其他问题,所以我使用了v-show,但这在开发人员控制台中给了我一个错误:

  

在同一渲染树中发现插槽“ page6”重复存在-   这可能会导致渲染错误。

以下是组件的结构。请注意,它们在同一.vue file

桌面代码段

<v-stepper-items>
    <v-stepper-content v-for="(item,index) in steps" :key="index" :step="index+1">
      <slot :name="item.slot"></slot>
    </v-stepper-content>
  </v-stepper-items>

移动代码段

<v-stepper-content :key="`${index}-stepContent-mobile`" :step="index+1">
    <slot :name="item.slot"></slot>
  </v-stepper-content>

我尝试执行广告位范围,但这似乎不适用

<v-stepper-items>
    <v-stepper-content v-for="(item,index) in steps" :key="index" :step="index+1">
      <template :slot-scope="item.slot"><slot :name="item.slot"></slot></template>
    </v-stepper-content>
  </v-stepper-items>

这是用户使用组件时如何设置插槽的方法,可以here

看到
 <div slot="page5">
    <h4>Step 3</h4>
  </div>

因此,这里的关键是用户在使用组件时设置了一个插槽,但是组件在.vue文件中的2个位置中放置了该插槽,其中一个位于桌面区域,另一个位于移动区域。但是,它必须具有相同的名称,因为它实际上是相同的插槽...

这是我的带有代码的github项目,您可以将其下拉并运行npm install,然后运行npm run dev以查看其运行情况:Vuetify-Simple-Wizard

2 个答案:

答案 0 :(得分:1)

您可以将组件分为 SimpleWizardMobile SimpleWizardDesk ,然后在SimpleWizard中使用动态组件模板,

模板

<template>
  <component :is="deviceType" 
    :completeStep="completeStep" 
    :previousStepLabel="previousStepLabel"
    :nextStepLabel="nextStepLabel"
    :steps="steps"
    :onNext="onNext"
    :onBack="onBack"
    :mobileBreakpoint="mobileBreakpoint"
    :theme="theme"
    ></component>
</template>

组件

<script>
import SimpleWizardDesk from './SimpleWizardDesk'
import SimpleWizardMobile from './SimpleWizardMobile'
...
computed: {
  deviceType() {
    return this.isMobile ? SimpleWizardMobile : SimpleWizardDesk
  }
},

我确认您的开发工具仍在使用此结构,但尚未解决所有的js重构(只是对每个JS使用了相同的组件并重构了模板)。

答案 1 :(得分:1)

您可以使用Portal-Vue将步槽多播到两个位置(台式和移动式)。

由于门户网站的目标名称可以是动态的,因此它在初始渲染后调整窗口大小时即可工作,即,isMobile的值更改时,门户网站会重新评估并将其内容移至适当的部分。

<v-stepper v-model="stepStage" :alt-labels="!isMobile" :vertical="isMobile" >
  <div v-show="!isMobile">
    ...
    <v-stepper-items>
      <v-stepper-content v-for="(item,index) in steps" :key="index" :step="index+1">
        <portal-target :name="`portal-desk-${index}`" :key="index" slim></portal-target>
      </v-stepper-content>
    </v-stepper-items>
    ...
  </div>
  <div v-show="isMobile">
    <template v-for="(item,index) in steps">
      ...
      <v-stepper-content :key="`${index}-stepContent-mobile`" :step="index+1">
        <portal-target :name="`portal-mobile-${index}`" :key="index" slim></portal-target>
      </v-stepper-content>
      ...
    </template>
  </div>  

  <template v-for="(item, index) in steps">
    <portal :to="portalName(index)" :key="index">
      <template :slot-scope="item.slot"><slot :name="item.slot"></slot></template>
    </portal>
  </template>

</v-stepper>
computed: {
  portalName() {
    return (index) => {
      const section = this.isMobile ? 'mobile' : 'desk';
      return `portal-${section}-${index}` 
    }
  }
},

v-if

我不确定您在v-if上发现了什么问题,但似乎可以在v-stepper-content上使用v-if

<div v-show="!isMobile">
  ...
  <v-stepper-content v-if="!isMobile" v-for="(item,index) in steps" :key="index" :step="index+1">
  ...
<div v-show="isMobile">
  ...
  <v-stepper-content v-if="isMobile" :key="`${index}-stepContent-mobile`" :step="index+1">