You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quasar/Vue3嵌套条件组件插槽无法加载问题求助

Quasar/Vue3 插槽内容无法加载问题排查

组件结构

  • IndexPage.vue:路由对应的页面组件
  • AwPage.vue:带插槽的包装组件,在IndexPage中使用
  • sub/PageDesktop等子组件:均包含3个插槽,被引入AwPage.vue中,根据条件渲染不同组件

当前问题

插槽内容无法加载,页面显示空白。

已尝试的解决方法

  • 移除markRaw和shallowRef,排查是否为阻塞因素
  • 移除<component :is="Pages[variant]" />写法
  • 直接引入单个PageDesktop组件无条件渲染,仍出现空白

组件代码示例

IndexPage.vue

<template>
  <AwPage variant="desktop">
    <template #sidebar>
      <AwSidebar :tags="tagsData" />
    </template>

    <template #list>
      <!-- <NotesList :notes="notesData" /> -->
      <NotesList :notes="notesData" />
    </template>

    <template #editor>
      <template v-if="!!$route.query.mode">
        <AwNoteEditor v-if="$route.query.mode === 'edit'" :notes="notesData" />
        <AwNoteView v-if="$route.query.mode === 'view'" :notes="notesData" />
      </template>
      <div v-else>
        <AwSelectNote />
      </div>
    </template>
  </AwPage>
</template>

<script setup lang="ts">
import AwPage from 'src/components/shared/AwPage/AwPage.vue';

const tagsData = tags;
const notesData = notes;
</script>

<style scoped lang="scss"></style>

AwPage.vue

<!-- eslint-disable vue/multi-word-component-names -->
<script setup lang="ts">
// import PageDesktop from './sub/PageDesktop.vue';
// import PageMobile from './sub/PageMobile.vue';
// import PageTablet from './sub/PageTablet.vue';

defineProps<{
  debug?: boolean;
  variant: 'desktop' | 'tablet' | 'mobile';
}>();

// const Pages = shallowRef({
//   desktop: PageDesktop,
//   tablet: PageTablet,
//   mobile: PageMobile,
// });

// console.log(Pages);
//
</script>

<template>
  <!-- <component :is="PageDesktop" :debug="debug" /> -->
  <PageDesktop />
</template>

<style scoped lang="scss">
@media (min-width: 1280px) {
  .responsive-section {
    display: none;
  }
}

@media (max-width: 1280px) {
  .q-drawer {
    display: block;
  }
  .note-view {
    display: none;
  }
  .note-list {
    width: 100%;
  }
  .side {
    width: 35.15%;
    flex-shrink: 0;
  }
  .list {
    width: 64.85%;
  }
  .list-name {
    display: none;
  }
}
</style>

PageDesktop.vue

<template>
  <q-page class="row justify-between">
    <section class="row justify-between t-w-[45%]">
      <aside class="t-w-[46.15%] side" :class="{ 'border-debug': debug }">
        <slot name="sidebar" />
      </aside>
      <div class="t-w-[53.85%] bg-dark" :class="{ 'border-debug': debug }">
        <slot name="list" />
      </div>
    </section>
    <section class="t-w-[54.86%]" :class="{ 'border-debug': debug }">
      <slot name="editor" />
    </section>
  </q-page>
</template>

<script setup lang="ts">
defineProps<{
  debug?: boolean;
}>();
</script>

需求概述

需要通过prop参数实现UI响应式布局,已创建对应尺寸CSS的3个页面组件,仅需传递prop即可根据屏幕尺寸渲染不同布局。

问题推测

问题并非出在插槽本身,而是AwPage没有将接收的插槽内容透传给内部渲染的子组件。直接在IndexPage中调用PageDesktop可正常工作,但不符合封装需求。

解决方案

核心是让AwPage把自身接收的插槽内容转发给内部动态渲染的布局组件,修改后的AwPage.vue如下:

<!-- eslint-disable vue/multi-word-component-names -->
<script setup lang="ts">
import PageDesktop from './sub/PageDesktop.vue';
import PageMobile from './sub/PageMobile.vue';
import PageTablet from './sub/PageTablet.vue';

defineProps<{
  debug?: boolean;
  variant: 'desktop' | 'tablet' | 'mobile';
}>();

const Pages = {
  desktop: PageDesktop,
  tablet: PageTablet,
  mobile: PageMobile,
};
</script>

<template>
  <component :is="Pages[variant]" :debug="debug">
    <!-- 透传所有具名插槽 -->
    <template #sidebar>
      <slot name="sidebar" />
    </template>
    <template #list>
      <slot name="list" />
    </template>
    <template #editor>
      <slot name="editor" />
    </template>
  </component>
</template>

<style scoped lang="scss">
@media (min-width: 1280px) {
  .responsive-section {
    display: none;
  }
}

@media (max-width: 1280px) {
  .q-drawer {
    display: block;
  }
  .note-view {
    display: none;
  }
  .note-list {
    width: 100%;
  }
  .side {
    width: 35.15%;
    flex-shrink: 0;
  }
  .list {
    width: 64.85%;
  }
  .list-name {
    display: none;
  }
}
</style>

关键修改点

  1. 重新引入三个布局子组件,用普通对象定义组件映射(无需shallowRef,静态映射直接用对象即可)
  2. 使用<component :is="Pages[variant]" />动态渲染对应布局组件
  3. 在动态组件内部,通过<template #插槽名>将AwPage接收的插槽内容透传给内部子组件
  4. 确保内部子组件的插槽名称与AwPage接收的插槽名称完全匹配

修改后,IndexPage传递给AwPage的插槽内容会被正确转发到对应的响应式布局组件中,页面即可正常显示内容。


内容的提问来源于stack exchange,提问作者Uncanny Coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 04:47:34