☰
在 Storybook 中编写 Tab 类型 Addon:`storybook/manager-api` 注册自定义标签页的完整实战
2026/10/24 16:30:36 网站建设 项目流程

在 Storybook 中编写 Tab 类型 Addon:storybook/manager-api注册自定义标签页的完整实战

【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook

本指南围绕官方 addon 类型文档中的storybook-addon-tab-example代码示例展开,讲解如何在 Storybook 的 manager UI 中新增一个自定义 Tab(标签页),并提供可直接复制运行的完整代码。读完本文,你将掌握addons.register与addons.add的用法、types.TAB标签页在 Storybook 内部如何被渲染与激活,以及如何把这段示例接入自己的.storybook配置并在 UI 中验证效果。

该示例正文收录于 docs/_snippets/storybook-addon-tab-example.md,被 docs/addons/addon-types.mdx 在讲解「Tabs」一节时通过CodeSnippets引用,是官方给出的「为 Storybook 添加自定义 Tab」最小样板。

背景:UI 型 Addon 的三大形态

Storybook 的 Addon 生态分为两类:UI-based addons(直接定制 manager UI)与Preset addons(打包 babel/webpack/addons 配置以集成第三方技术栈)。其中 UI 型 addon 又细分为三种形态(详见 docs/addons/addon-types.mdx):

UI 形态作用代表
Panel(面板)在 Addon Panel 中加入自己的 UI,是生态中最常见的形态@storybook/addon-a11y
Toolbar(工具栏)在 Storybook 顶部 Toolbar 添加自定义工具按钮@storybook/addon-themes
Tab(标签页)在 Storybook 预览区创建你自己的标签页,用于替换/扩展 Canvas本文示例

Tab 形态允许 addon 提供一整块自定义视图,典型用途包括:独立的调试控制台、自定义预览、按项目需求定制的可视化检查器。官方示例的运行效果如下方截图所示(图片来源 docs/_assets/addons/storybook-tab.png):

最小可用示例:为 Storybook 添加一个自定义 Tab

storybook-addon-tab-example示例的完整代码如下(运行在 manager 环境,即 Storybook 的 UI 外壳进程中,而非渲染 Story 的 iframe 中):

import React from 'react'; import { addons, types } from 'storybook/manager-api'; addons.register('my-addon', () => { addons.add('my-addon/tab', { type: types.TAB, title: 'Example Storybook tab', render: () => ( <div> <h2>I'm a tabbed addon in Storybook</h2> </div> ), }); });

逐行拆解这段代码:

  1. import React from 'react':Tab 的内容由render返回,Storybook manager 基于 React 构建,因此渲染函数可直接使用 JSX。
  2. import { addons, types } from 'storybook/manager-api':当前仓库版本中,操作 manager UI 的 API 统一从storybook/manager-api导入(对应文档见 docs/addons/addons-api.mdx)。
  3. addons.register('my-addon', ...):所有 addon 的入口。它把加载函数登记到一个以 id 为键的注册表中,并在 Storybook 启动时通过loadAddons统一调用,随后 addon 代码可访问完整的 Storybook API 实例。
  4. addons.add('my-addon/tab', ...):把 UI 组件注册进 addon store。add()内部以type归类存储,等同于往TAB类型集合中放入一个元素{ ...addon, id }(见源码 code/core/src/manager-api/lib/addons.ts)。
  5. type: types.TAB:声明该 UI 元素属于「标签页」。types正是内部枚举Addon_TypesEnum的别名(源码 code/core/src/manager-api/lib/addons.ts),Storybook 会据此把 addon 挂载到标签页容器。
  6. title:标签页上显示的标题文本,即用户看到的 Tab 名称。
  7. render:渲染 addon 组件内容的函数。

标签页在 manager 内部如何被消费

自定义 Tab 并不是悬空的概念,Storybook 内部把默认的画布 Canvas 本身也定义为一个types.TAB元素。在源码 code/core/src/manager/components/preview/Preview.tsx 中:

export const createCanvasTab = (): Addon_BaseType => ({ id: 'canvas', type: types.TAB, title: 'Canvas', route: ({ storyId, refId }) => (refId ? `/story/${refId}_${storyId}` : `/story/${storyId}`), match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)), render: () => null, });

由此可还原出完整的消费链路:

  • 全部 Tab(内置canvas与各个 addon 注册的 Tab)被聚合后交给useTabsState管理选中态,选中项通过 URL 查询参数tab=<id>反映(代码见 Preview.tsx)。
  • 每个 Tab 的渲染体被包裹为children: () => tab.render({ active: true }),即render函数在渲染时会被调用,并传入active参数;当某个 Tab 获得焦点时active为真。
  • 未被选中的 Tab 内容不可见;选中某个自定义 Tab 后,其render的返回值会占据IframeWrapper区域,而 Canvas 画布仅在tabId为空或为'canvas'时才显示(Preview.tsx)。

换句话说,自定义 Tab 实质是在「Canvas / Docs」之外新增一类视图模式,与内置画布平行存在。此外filterTabs(Preview.tsx)支持通过previewTabs参数对标签页做重排序、重命名、隐藏等定制,addon 也可以借此控制自己标签页的展示顺序。

关于route与match(进阶可选字段)

内置 canvas Tab 展示了Addon_BaseType上的两个可选字段:

  • route:根据当前storyId/refId推导选中该 Tab 时对应的路由;
  • match:根据当前viewMode等状态判断该 Tab 是否处于激活匹配状态。

撰写普通内容型 Tab 时并非强制要求,但若希望 Tab 与「story/docs 视图」联动或需要控制可见范围,可以参考内置 canvas 的实现补充这两个字段。match字段同样作用于 toolbar 类 addon 的条件渲染,官方在 docs/addons/writing-addons.mdx 中有更完整的说明。

让这个 addon 真正出现在你的 Storybook 中

示例代码位于 addon 的manager 入口文件中。要让 Storybook 加载它,需要把该入口注册进 manager bundle。可参考仓库文档 docs/addons/writing-addons.mdx 中本地 addon 的标准接线方式:在 addon 的预设(preset)中声明managerEntries,例如:

// 你的 addon 目录下,预设文件(如 preset.js / index.js) module.exports = { managerEntries: ['addon-tab/manager.js'], };

随后在.storybook/main.js的addons数组中把该本地目录加进去,例如:

export default { stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], addons: ['./addon-tab'], };

启动 Storybook 开发服务器(仓库中的code工作区可执行yarn storybook:ui这类脚本启动本地示例,见 code/package.json),即可在预览区顶部看到标题为Example Storybook tab的新标签页。点击它,页面主体会替换为render返回的<h2>I'm a tabbed addon in Storybook</h2>内容,URL 会携带?tab=my-addon/tab参数,刷新页面后也能保持选中状态。

编写 Tab addon 的工程要点

结合示例与源码,这里给出几条可直接照搬的实践建议:

  • id 使用命名空间式字符串:示例中 addon 注册名为my-addon,Tab 元素 id 为my-addon/tab,二者都带前缀避免与内置canvas或其他 addon 冲突。注意register时若同一 id 被加载两次,manager 会打印警告日志(见 code/core/src/manager-api/lib/addons.ts)。
  • title与render是必需项:官方 addon API 文档明确,一个最小 UI addon 至少要提供type、title、render三个参数(见 docs/addons/addons-api.mdx 中addons.add()一节)。
  • 只引入 manager 侧包:manager 环境会在全局作用域提供部分包(React、manager-api 等),addon 代码从storybook/manager-api导入即可,不必重复声明为运行依赖。
  • 了解 Tab 能力的边界与演进:从源码注释可以确认,当前版本把自定义 addon Tab 视为「少数派且计划淘汰」的特性——当检测到多于一个 Tab 时会触发Addon tabs are deprecated and will be removed in Storybook 11的弃用提示(code/core/src/manager/components/preview/Preview.tsx)。因此新项目优先考虑 Panel/Toolbar 形态,或在评估 Tab 形态时知晓其长期走向。

延伸阅读

  • Addon 类型总览:Panel / Toolbar / Tab / Preset 四种形态的横向对比与官方样板。
  • Addon API 参考:addons.add、addons.register、getChannel、setConfig及全套useStorybookState/useChannel等 Hooks。
  • 编写 Addon:manager 入口、预设接线、match条件渲染等完整开发流程。
  • manager-api 源码:addon store 的单例实现、元素分类存储与加载机制。
  • Preview 组件源码:内置 canvas Tab 定义、标签页选中态与查询参数同步逻辑。

【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询