Vue3组件多布局变体的无冗余代码实现方案咨询
Vue3 布局变体优化方案
针对你遇到的两种布局变体代码冗余问题,以下是几种简洁的实现方式:
方案1:模板内仅判断差异部分
只在布局的差异节点做条件判断,公共结构复用,避免全量代码重复:
<script setup> const props = defineProps({ layout: { type: String, default: 'top-row', validator: val => ['top-row', 'left-col'].includes(val) } }) </script> <template> <div class="flex flex-col"> <div class="flex"> <InnerComponent1 /> <!-- 第一处差异:顶部布局显示InnerComponent2,左侧布局显示插槽 --> <InnerComponent2 v-if="layout === 'top-row'" /> <slot v-else /> </div> <!-- 第二处差异:顶部布局显示插槽,左侧布局显示InnerComponent2 --> <slot v-if="layout === 'top-row'" /> <InnerComponent2 v-else /> </div> </template>
方案2:使用渲染函数(h函数)
通过JS逻辑生成VNode,把布局结构封装成函数,适合需要动态调整结构的场景:
<script setup> import { h } from 'vue' import InnerComponent1 from './InnerComponent1.vue' import InnerComponent2 from './InnerComponent2.vue' const props = defineProps({ layout: { type: String, default: 'top-row', validator: val => ['top-row', 'left-col'].includes(val) } }) const renderLayout = () => { const innerContent = props.layout === 'top-row' ? [h(InnerComponent1), h(InnerComponent2)] : [h(InnerComponent1), h('slot')] const bottomContent = props.layout === 'top-row' ? h('slot') : h(InnerComponent2) return h('div', { class: 'flex flex-col' }, [ h('div', { class: 'flex' }, innerContent), bottomContent ]) } </script> <template> <render-layout /> </template>
方案3:拆分为布局子组件
把两种布局封装成独立子组件,主组件根据props动态渲染,适合布局后续可能扩展的场景:
先创建两个布局子组件
LayoutTopRow.vue:
<template> <div class="flex flex-col"> <div class="flex"> <InnerComponent1 /> <InnerComponent2 /> </div> <slot /> </div> </template>
LayoutLeftCol.vue:
<template> <div class="flex flex-col"> <div class="flex"> <InnerComponent1 /> <slot /> </div> <InnerComponent2 /> </div> </template>
主组件动态渲染
<script setup> import { defineAsyncComponent } from 'vue' const props = defineProps({ layout: { type: String, default: 'top-row', validator: val => ['top-row', 'left-col'].includes(val) } }) // 按需加载对应布局组件 const LayoutComponent = defineAsyncComponent(() => { return props.layout === 'top-row' ? import('./LayoutTopRow.vue') : import('./LayoutLeftCol.vue') }) </script> <template> <LayoutComponent> <slot /> </LayoutComponent> </template>
选择建议
- 布局差异极小:选方案1,代码最直观,学习成本低
- 需要动态生成复杂结构:选方案2,灵活性更高
- 布局后续可能迭代扩展:选方案3,模块化更强,便于维护
内容的提问来源于stack exchange,提问作者Artem Shalagin
相关产品推荐
相关产品推荐

