【问题标题】:How to use duplicate named slots in Vue如何在 Vue 中使用重复的命名槽
【发布时间】:2018-09-28 09:22:25
【问题描述】:

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

我需要为桌面视图和移动视图提供此插槽。我尝试使用 v-if 来隐藏是否移动,但这会导致其他问题,所以我选择了 v-show,但这在开发者控制台中出现了错误:

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

这是组件的结构请注意,它们在同一个.vue file

桌面sn-p

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

手机sn-p

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

所以这里的关键是用户在使用组件的时候设置了一个slot,但是组件把那个slot放在了.vue文件的2个地方,一个在桌面部分,一个在移动部分。但是,它需要具有相同的名称,因为它实际上是同一个插槽...

这是我的 github 项目的代码,您可以将其拉下并运行 npm install,然后运行 ​​npm run dev 以查看它的实际效果:Vuetify-Simple-Wizard

【问题讨论】:

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


    【解决方案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-如果

    我不确定你在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">
    

    【讨论】:

    • 这看起来很有希望!谢谢你!我对 v-if 的问题是 v-stepper 没有正确读取 stepStage 并且没有将第一阶段设置为活动状态。即使在强制渲染、安装等情况下,它也不会将舞台设置为活动状态,直到我按下下一个按钮。我可以通过将阶段设置为 0 并触发来绕过它,但感觉不对。我刚刚注意到你是在 v-stepper-content 上做的,由于垂直和水平 v-stepper 的结构不同,我做得更高。
    • 刚刚试了一下,我觉得这是正确的答案。但是有些东西是关闭的,它没有将插槽设置​​为门户目标,它只是一个空元素。很可能我没有正确使用它,但我只是将更改推送到 simplewizard.vue 文件...
    • 我也一直在研究它,发布的代码不正确。门户元素需要&lt;template v-for="(item, index) in steps"&gt; 包装器,并且门户名称必须是唯一的。为此,我使用了一个计算属性,它以portal-mobile-1portal-desk-1 等格式返回字符串。现在步骤内容在正确的位置。
    • 最后剩下的问题是所有stepper-content元素都有display: none属性,我确定这是由vuetify设置的,但不知道为什么(通常当前的stepper-content不显示:无,它会随着您的步骤而改变)。解决后将发布修订。
    • 步进器内容显示通常由与步进器的 v-model 匹配的“step”属性设置,标题项也是如此......仍在工作中
    【解决方案2】:

    您可以将组件分解为 SimpleWizardMobileSimpleWizardDesk,然后在 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 重构(只是为每个组件使用相同的组件并重构模板)。

    【讨论】:

    • 感谢您的回复!我担心这可能是我唯一的选择......我的挂断绝对是关于如何处理 JavaScript 部分,特别是因为它大部分是完全相同的......我要做更多的挖掘,然后也许给这个试一试。
    猜你喜欢
    • 1970-01-01
    • 2018-08-05
    • 1970-01-01
    • 2020-05-27
    • 1970-01-01
    • 2017-09-08
    • 2021-02-06
    • 2021-02-10
    • 2021-06-03
    相关资源
    最近更新 更多