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>
关键修改点
- 重新引入三个布局子组件,用普通对象定义组件映射(无需
shallowRef,静态映射直接用对象即可) - 使用
<component :is="Pages[variant]" />动态渲染对应布局组件 - 在动态组件内部,通过
<template #插槽名>将AwPage接收的插槽内容透传给内部子组件 - 确保内部子组件的插槽名称与
AwPage接收的插槽名称完全匹配
修改后,IndexPage传递给AwPage的插槽内容会被正确转发到对应的响应式布局组件中,页面即可正常显示内容。
内容的提问来源于stack exchange,提问作者Uncanny Coder
相关产品推荐
相关产品推荐

