DockLayout 多面板布局
递归 split + tabbed pane 的桌面应用布局壳。v1 声明式布局,v2 加入拖拽重排。
基础用法
布局以一棵 DockGroup 树声明:每个 group 要么有 children(继续切分)要么有 panels(这是一个 tabbed 区域)。
内容通过 named slot panel-{id}(Vue)/ slots["panel-{id}"](React)提供。
背景
<script setup lang="ts">
import { CfDockLayout } from '@chufix-design/vue';
import type { DockGroup } from '@chufix-design/vue';
const layout: DockGroup = {
id: 'root',
orientation: 'horizontal',
children: [
{
id: 'left',
orientation: 'vertical',
panels: [
{ id: 'tree', title: 'Explorer', closable: false },
],
size: '240px',
},
{
id: 'main',
orientation: 'vertical',
children: [
{
id: 'editor',
orientation: 'horizontal',
panels: [
{ id: 'orders', title: 'orders.ts', closable: true, detachable: true },
{ id: 'login', title: 'login.ts', closable: true, detachable: true },
],
},
{
id: 'bottom',
orientation: 'horizontal',
panels: [
{ id: 'terminal', title: 'Terminal', closable: false },
{ id: 'output', title: 'Output', closable: false },
],
size: '160px',
},
],
},
],
};
</script>
<template>
<div style="height: 360px; border: 1px solid var(--line-1); border-radius: var(--r-6); overflow: hidden;">
<CfDockLayout :layout="layout">
<template #panel-tree>
<ul style="padding: 12px 16px; margin: 0; list-style: none; font-size: 12px; color: var(--fg-2);">
<li>📁 src</li>
<li style="padding-left: 14px;">📄 orders.ts</li>
<li style="padding-left: 14px;">📄 login.ts</li>
</ul>
</template>
<template #panel-orders>
<pre style="margin: 0; padding: 12px 16px; font-family: var(--font-mono); font-size: 12px; color: var(--fg-1);">// orders.ts
export const fetchOrders = () => …</pre>
</template>
<template #panel-login>
<pre style="margin: 0; padding: 12px 16px; font-family: var(--font-mono); font-size: 12px; color: var(--fg-1);">// login.ts
export const login = () => …</pre>
</template>
<template #panel-terminal>
<pre style="margin: 0; padding: 12px 16px; font-family: var(--font-mono); font-size: 12px; color: var(--fg-1);">$ pnpm dev
[vite] dev server running on :5173</pre>
</template>
<template #panel-output>
<pre style="margin: 0; padding: 12px 16px; font-family: var(--font-mono); font-size: 12px; color: var(--fg-2);">[14:32:01] Build succeeded</pre>
</template>
</CfDockLayout>
</div>
</template> <script setup>
import { CfDockLayout } from '@chufix-design/vue';
const layout= {
id: 'root',
orientation: 'horizontal',
children: [
{
id: 'left',
orientation: 'vertical',
panels: [
{ id: 'tree', title: 'Explorer', closable: false },
],
size: '240px',
},
{
id: 'main',
orientation: 'vertical',
children: [
{
id: 'editor',
orientation: 'horizontal',
panels: [
{ id: 'orders', title: 'orders.ts', closable, detachable: true },
{ id: 'login', title: 'login.ts', closable, detachable: true },
],
},
{
id: 'bottom',
orientation: 'horizontal',
panels: [
{ id: 'terminal', title: 'Terminal', closable: false },
{ id: 'output', title: 'Output', closable: false },
],
size: '160px',
},
],
},
],
};
</script>
<template>
<div style="height: 360px; border: 1px solid var(--line-1); border-radius: var(--r-6); overflow: hidden;">
<CfDockLayout :layout="layout">
<template #panel-tree>
<ul style="padding: 12px 16px; margin: 0; list-style: none; font-size: 12px; color: var(--fg-2);">
<li>📁 src</li>
<li style="padding-left: 14px;">📄 orders.ts</li>
<li style="padding-left: 14px;">📄 login.ts</li>
</ul>
</template>
<template #panel-orders>
<pre style="margin: 0; padding: 12px 16px; font-family: var(--font-mono); font-size: 12px; color: var(--fg-1);">// orders.ts
export const fetchOrders = () => …</pre>
</template>
<template #panel-login>
<pre style="margin: 0; padding: 12px 16px; font-family: var(--font-mono); font-size: 12px; color: var(--fg-1);">// login.ts
export const login = () => …</pre>
</template>
<template #panel-terminal>
<pre style="margin: 0; padding: 12px 16px; font-family: var(--font-mono); font-size: 12px; color: var(--fg-1);">$ pnpm dev
[vite] dev server running on :5173</pre>
</template>
<template #panel-output>
<pre style="margin: 0; padding: 12px 16px; font-family: var(--font-mono); font-size: 12px; color: var(--fg-2);">[14:32:01] Build succeeded</pre>
</template>
</CfDockLayout>
</div>
</template> <CfDockLayout layout={layout} slots={{
'panel-orders': <pre>orders.ts</pre>,
'panel-login': <pre>login.ts</pre>,
'panel-terminal': <Terminal />,
}} /> <CfDockLayout layout={layout} slots={{
'panel-orders': <pre>orders.ts</pre>,
'panel-login': <pre>login.ts</pre>,
'panel-terminal': <Terminal />,
}} /> 最简布局(无嵌套)
一个 group + 多个 panels = 普通 tabbed 视图,等价于 CfTabs;当只有 tab 切换需求时直接用 CfTabs 更轻。
背景
<script setup lang="ts">
import { CfDockLayout } from '@chufix-design/vue';
import type { DockGroup } from '@chufix-design/vue';
const layout: DockGroup = {
id: 'root',
orientation: 'vertical',
panels: [
{ id: 'preview', title: '预览', closable: false },
{ id: 'console', title: 'Console', closable: false },
],
};
</script>
<template>
<div style="height: 240px; border: 1px solid var(--line-1); border-radius: var(--r-6); overflow: hidden;">
<CfDockLayout :layout="layout">
<template #panel-preview>
<div style="padding: 16px; color: var(--fg-2);">预览区(这是一个仅 tab 切换的简化布局)</div>
</template>
<template #panel-console>
<pre style="margin: 0; padding: 16px; font-family: var(--font-mono); font-size: 12px; color: var(--fg-2);">$ ready
[14:32] /v1/orders → 200 OK · 288ms</pre>
</template>
</CfDockLayout>
</div>
</template> <script setup>
import { CfDockLayout } from '@chufix-design/vue';
const layout= {
id: 'root',
orientation: 'vertical',
panels: [
{ id: 'preview', title: '预览', closable: false },
{ id: 'console', title: 'Console', closable: false },
],
};
</script>
<template>
<div style="height: 240px; border: 1px solid var(--line-1); border-radius: var(--r-6); overflow: hidden;">
<CfDockLayout :layout="layout">
<template #panel-preview>
<div style="padding: 16px; color: var(--fg-2);">预览区(这是一个仅 tab 切换的简化布局)</div>
</template>
<template #panel-console>
<pre style="margin: 0; padding: 16px; font-family: var(--font-mono); font-size: 12px; color: var(--fg-2);">$ ready
[14:32] /v1/orders → 200 OK · 288ms</pre>
</template>
</CfDockLayout>
</div>
</template> <CfDockLayout layout={{ id: "r", orientation: "vertical", panels: [...] }} /> <CfDockLayout layout={{ id: "r", orientation: "vertical", panels: [...] }} /> API
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
layout | DockGroup | — | 布局描述树 |
active | Record<groupId, panelId> | {} | 各 group 的活动 tab id |
DockGroup:{ id, orientation: 'horizontal' \| 'vertical', children?: DockGroup[], panels?: DockPanel[], size? }
DockPanel:{ id, title, contentKey?, closable?, detachable?, size?, collapsed? }
事件:active-change(groupId, panelId) / panel-close(...) / panel-detach(...)。
v1 限制:splitter resize 与 drag-to-rearrange 暂未支持,将在 v2 加入。
反馈与讨论
DockLayout 多面板布局 的讨论