Storybook 实战:基于 Story 标签按需隐藏插件面板(addon panel)的layoutCustomisations.showPanel指南
【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook
本篇技术指南围绕 Storybook 的 manager 侧 APIaddons.setConfig与layoutCustomisations.showPanel展开,讲解如何针对特定 Story(如带showcase、kitchensink标签的"展示型"Story)自动隐藏 addon 面板,让展示页回归纯粹的画布体验。读完你将掌握showPanel的函数签名、State参数各字段含义、与showSidebar/showToolbar的组合用法,以及其底层在 manager-api 中的真实实现原理。
为什么需要按 Story 隐藏 addon 面板
Storybook 在查看 Story 时,默认在画布下方(或右侧)显示 addon 面板,用于呈现 Controls、Actions、Interactions、A11y 等插件的 UI(相关面板见 interaction-testing、accessibility-testing、controls 等文档)。但对于专门用来"展示"组件多种变体或使用示例的 Story(例如组件画廊页、kitchen-sink 页、landing 页),面板往往没有实际调试价值,反而挤占画布空间、干扰演示效果。
此时需要一种按 Story 维度精细控制面板显隐的能力,而不是全局一刀切地开关面板。Storybook 的 manager 配置项layoutCustomisations.showPanel正是为此设计:它是一个以"当前 UI 状态"为输入、返回"是否显示面板"的高阶函数,可以读取当前 Story 的标签(tags)、viewMode、storyId等上下文,决定false(隐藏)或回退到用户的默认偏好。
layoutCustomisationsAPI 总览
layoutCustomisations是addons.setConfig下的一个命名空间,用于对 Storybook 三大 UI 区域做条件化显隐控制。从源码类型定义 api.ts 可以看到它的完整结构:
export interface API_LayoutCustomisations { showPanel?: (state: State, defaultValue: boolean) => boolean | undefined; showSidebar?: (state: State, defaultValue: boolean) => boolean | undefined; showToolbar?: (state: State, defaultValue: boolean) => boolean | undefined; }三个回调函数签名一致:接收完整的 UIState与一个defaultValue(表示当前是否显示的默认值),返回true/false覆盖默认行为,返回undefined则视为"不干预"。该配置通过 addons.ts 中的layoutCustomisations?: Partial<API_LayoutCustomisations>挂载到addons.setConfig的参数类型上。
官方文档 features-and-behavior.mdx 中给出的三个配置项及其作用如下:
| 配置项 | 类型 | 作用 |
|---|---|---|
showSidebar | Function | 条件控制侧边栏显隐 |
showToolbar | Function | 条件控制顶部工具栏显隐 |
showPanel | Function | 条件控制 addon 面板显隐(本文主题) |
对应的完整配置示例(同时覆盖三个函数)见 storybook-config-layout.md。这些回调函数都允许"包含一些默认行为并可按需覆盖",从而在保留用户偏好(如用户手动打开/关闭面板)的前提下,对特定页面强制显隐。
showPanel函数签名与State参数详解
showPanel(state, defaultValue)的第一个参数是当前 manager 的完整状态对象,官方文档为它列出了可直接使用的字段:
| 字段 | 类型 | 含义 | 示例值 |
|---|---|---|---|
path | String | 当前展示页面的路径 | '/story/components-button--default' |
viewMode | String | 当前页面是 story 还是 docs | 'docs'或'story' |
singleStory | Boolean | 当前组件是否只有一个 Story | true/false |
storyId | String | 当前 Story 或 docs 页的 id | 'blocks-unstyled--docs' |
index | Object | 静态分析得到的全部 Story 元数据索引 | { 'blocks-unstyled--docs': { tags: ['autodocs'] } } |
layout | Object | 当前布局状态(见下) | — |
layout.isFullscreen | Boolean | 画布是否处于全屏模式 | true/false |
layout.panelPosition | String | 面板位于下方还是侧边 | 'bottom'/'right' |
layout.showNav | Boolean | 用户是否想看到侧边栏 | true/false |
layout.showPanel | Boolean | 用户是否想看到面板 | true/false |
layout.showToolbar | Boolean | 用户是否想看到工具栏 | true/false |
对本文场景最关键的是state.index?.[state.storyId]?.tags:index中保存了每个 Story 的静态分析元数据(含tags),配合当前storyId即可拿到当前 Story 的标签数组,从而实现"按标签隐藏面板"。
核心实现:基于showcase/kitchensink标签隐藏面板
以下代码来自官方示例片段 storybook-manager-addon-panel-hide-on-showcase.md,直接放入你的 manager 配置文件(./storybook/manager.js,TypeScript 项目为./storybook/manager.ts)即可生效。JavaScript 版本:
import { addons } from 'storybook/manager-api'; addons.setConfig({ layoutCustomisations: { showPanel(state, defaultValue) { const tags = state.index?.[state.storyId]?.tags ?? []; // Hide the panel on stories designed to showcase multiple variants or usage examples. if (tags.includes('showcase') || tags.includes('kitchensink')) { return false; } return defaultValue; }, }, });TypeScript 版本:
import { addons, type State } from 'storybook/manager-api'; addons.setConfig({ layoutCustomisations: { showPanel(state: State, defaultValue: boolean) { const tags = state.index?.[state.storyId]?.tags ?? []; // Hide the panel on stories designed to showcase multiple variants or usage examples. if (tags.includes('showcase') || tags.includes('kitchensink')) { return false; } return defaultValue; }, }, });逐行拆解
- 读取标签:
state.index?.[state.storyId]?.tags ?? []—— 使用可选链安全取值,storyId不存在或tags缺失时回退为空数组,避免抛错; - 条件判断:若当前 Story 带
showcase或kitchensink标签,直接返回false,强制隐藏面板——这类 Story 通常是"集中展示多个变体/使用示例"的画廊页,不需要 Controls 等调试面板; - 回退默认:其余 Story 返回
defaultValue,即完全尊重用户当前的显隐偏好,不影响正常调试流程。
要使用这一能力,你需要先在对应 Story 的 CSF 文件中声明标签(例如tags: ['showcase']),这与autodocs、test等 Storybook 内建标签机制一致,Story 的元数据随后会被静态分析进state.index,供 manager 侧读取。
底层原理:getShowPanelWithCustomisations如何工作
从源码看,manager-api 的布局模块 layout.ts 中,面板显隐的自定义逻辑如下:
getShowPanelWithCustomisations(showPanel: boolean) { const state = store.getState(); if (isFunction(state.layoutCustomisations.showPanel)) { return state.layoutCustomisations.showPanel(state, showPanel) ?? showPanel; } return showPanel; },可以提炼出三个关键机制:
- 调用时机:Storybook 渲染 manager UI 时,会先把"当前面板是否显示"作为
showPanel传入,再调用你在layoutCustomisations.showPanel中注册的回调; ??空值合并:回调返回undefined时(等价于"不表态"),结果回退为传入的showPanel默认值,这正是示例代码中"非展示类 Story 返回defaultValue"这一分支能在源码层面成立的原因;- 未配置时的默认行为:默认布局状态 layout.ts 中
showPanel/showSidebar/showToolbar初始均为undefined,isFunction判断不通过时直接透传默认值,保证不配置该功能时行为与旧版完全一致。
同样的模式也应用于工具栏(getShowToolbarWithCustomisations)与侧边栏(getNavSizeWithCustomisations,通过将navSize置 0 来隐藏侧边栏)。layoutCustomisations配置本身在setConfig初始化时与默认状态合并(见 layout.ts),你只需提供Partial的片段即可,未提供的项保持默认。
实战扩展:与其他布局自定义组合使用
showPanel常与showSidebar、showToolbar组合,针对不同页面做差异化布局。仓库中提供了两个官方示例:
- 在 landing 页隐藏侧边栏:storybook-manager-sidebar-hide-on-landing.md 展示了当
storyId === 'landing' && viewMode === 'docs'时返回false隐藏侧边栏,因为该页面自带导航链接; - 在 docs 页隐藏工具栏:storybook-manager-toolbar-hide-on-docs.md 展示了当
viewMode === 'docs'时隐藏工具栏。
更完整的组合配置示例见 storybook-config-layout.md,其中showSidebar、showToolbar、navSize、bottomPanelHeight、panelPosition、initialActive等参数一应俱全。
通过 URL 参数临时控制
除了配置代码,Storybook 还支持 URL 查询参数对部分布局能力做运行时覆盖(见 features-and-behavior.mdx):
| 配置项 | 查询参数 | 支持值 |
|---|---|---|
| (全屏) | full | true、false |
| (显示侧边栏) | nav | true、false |
| (显示面板) | panel | false、'right'、'bottom' |
selectedPanel | addonPanel | 任意面板 ID |
showTabs | tabs | true |
| — | instrument | false、true |
| — | statuses | 分号分隔的状态值:new、modified、related(前缀!表示排除) |
例如在浏览器地址栏追加?panel=false即可临时隐藏面板,适合快速验证效果,无需改动配置文件。
注意事项与最佳实践
- 不要滥用隐藏能力:官方文档特别警告,
showSidebar与showToolbar可以隐藏对 Storybook 功能至关重要的 UI 元素,误用可能导致无法导航。隐藏侧边栏时,必须确保当前页面提供替代的导航方式(如 landing 页自带导航链接)。showPanel相对安全,但仍建议只针对明确的展示型 Story 生效; - 优先使用
defaultValue回退:示例中"命中标签返回false,否则返回defaultValue"的模式应当保持——这样不会覆盖用户手动开关面板的偏好,属于对用户最友好的实现; - 标签命名自洽:
showcase、kitchensink是示例中的约定标签,实际项目中你可以在 CSF 里自定义任意标签名,只要保证"Story 中声明的标签"与"showPanel中检查的标签"一致即可;仓库自身的 kitchen-sink 类示例项目(见 test-storybooks/portable-stories-kitchen-sink)也体现了这类"展示型 Story 集合"的真实使用场景; - 配置位置:该配置属于 manager 侧,应放在
storybook/manager.js/storybook/manager.ts(部分项目模板为.storybook/目录),而不是preview配置文件,因为addons与addons.setConfig均来自storybook/manager-api包。
总结
layoutCustomisations.showPanel为 Storybook 提供了"上下文感知"的面板显隐控制:借助state.index与 Story 标签机制,你可以精确地让展示型 Story(showcase/kitchensink)隐藏 addon 面板、回归纯净画布,同时在其他 Story 上完全保留用户的默认偏好。其背后由 manager-api 布局模块的getShowPanelWithCustomisations与??回退语义支撑,行为清晰可预期。配合showSidebar、showToolbar与 URL 参数,你可以为不同的查看场景定制出真正贴合演示与调试需求的 Storybook 界面。
【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考