
Storybook globalTypes 配置指南在 preview 中声明全局变量与工具栏【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook本篇技术指南讲解 Storybook 中如何在.storybook/preview.*配置文件里通过globalTypes与initialGlobals声明全局变量Globals并利用toolbar注解在 Storybook 工具栏生成下拉菜单从而让主题、语言等非故事级输入可以在整个组件工作台内被统一切换与消费。读完本文你将掌握globalTypes的完整配置语法覆盖 CSF 3 与 CSF Next 两代写法、toolbar各配置项的含义、MenuItem形状的字段说明以及如何用装饰器读取context.globals驱动所有故事的渲染。什么是 Globals为什么需要 globalTypes在 Storybook 中Globals 代表全局的而非某个故事特有的渲染输入。与args不同它们不会作为参数传给故事函数而是作为context.globals暴露给装饰器decorator供所有故事统一使用——这正是主题theme、语言locale、方向direction这类需要跨故事保持一致的状态的天然载体。globals 改变时故事会重新渲染装饰器也会以新值重新执行。而最便捷的改变 globals 的方式就是为它创建一个工具栏项。声明一个全局变量需要两个部分见 story.ts 中ProjectAnnotations的类型定义globalTypes声明全局变量的元信息包含description以及可选的toolbar注解两者都只能定义在项目级的.storybook/preview.*中不能在组件或故事级别声明。initialGlobals为这些全局变量提供初始值。从源码看二者的分工非常清晰GlobalsStore.ts 在set()时把globalTypes的键与initialGlobals的键合并为allowedGlobalNames这意味着只有被声明的全局变量才会被允许设置未声明即被写入会触发告警见 filterAllowedGlobals。最小配置声明一个 theme 全局变量与工具栏下面这段配置即本篇主题文档 storybook-preview-configure-globaltypes.md 的核心内容在.storybook/preview.js中声明了一个theme全局变量并在工具栏生成一个可切换light/dark的下拉菜单const preview { globalTypes: { theme: { description: Global theme for components, toolbar: { // The label to show for this toolbar item title: Theme, icon: circlehollow, // Array of plain string values or MenuItem shape (see below) items: [light, dark], // Change title based on selected value (recommended for consistency with the Storybook UI) dynamicTitle: true, }, }, }, initialGlobals: { theme: light, }, }; export default preview;启动 Storybook 后工具栏上就会出现一个包含light和dark两个选项的下拉菜单。配合initialGlobals: { theme: light }所有故事初始都会以light状态渲染。TypeScript 版本CSF 3使用 TypeScript 时可以借助框架提供的Preview类型获得完整的类型检查// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Preview } from storybook/your-framework; const preview: Preview { globalTypes: { theme: { description: Global theme for components, toolbar: { title: Theme, icon: circlehollow, items: [light, dark], dynamicTitle: true, }, }, }, initialGlobals: { theme: light, }, }; export default preview;GlobalTypes的类型在 story.ts 中被定义为{ [name: string]: ToolbarArgType }其内部结构详见 toolbar/types.tsname、description、defaultValue与toolbar都是可选字段。CSF Next 语法实验性若项目使用新一代 CSFCSF Next 可以用definePreview()替代对象导出配置内容完全一致。不同框架的导入路径略有差异// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite) import { definePreview } from storybook/your-framework; export default definePreview({ globalTypes: { theme: { description: Global theme for components, toolbar: { title: Theme, icon: circlehollow, items: [light, dark], dynamicTitle: true, }, }, }, initialGlobals: { theme: light, }, });Vue 与 Angular 的导入路径分别为storybook/vue3-vite和storybook/angularimport { definePreview } from storybook/vue3-vite; export default definePreview({ globalTypes: { theme: { description: Global theme for components, toolbar: { title: Theme, icon: circlehollow, items: [light, dark], dynamicTitle: true, }, }, }, initialGlobals: { theme: light, }, });import { definePreview } from storybook/angular; export default definePreview({ globalTypes: { theme: { description: Global theme for components, toolbar: { title: Theme, icon: circlehollow, items: [light, dark], dynamicTitle: true, }, }, }, initialGlobals: { theme: light, }, });Web Components 框架则使用storybook/web-components-vite写法完全相同。toolbar 注解各配置项详解toolbar注解是让全局变量可交互的关键。根据 toolbar/types.ts 中NormalizedToolbarConfig的类型定义其字段如下配置项类型说明titleString工具栏项显示的名称标签iconString工具栏项使用的图标名称取自storybook/icons图标集itemsArray选项列表元素可以是纯字符串也可以是MenuItem形状的对象dynamicTitleBoolean为true时工具栏按钮的标题会随当前选中项动态变化推荐开启以保持与 Storybook UI 一致preventDynamicIconBoolean设为true可阻止工具栏图标自动切换为当前选中项定义的图标shortcutsObject为上一个 / 下一个 / 重置操作绑定键盘快捷键其中title与icon的行为在渲染组件 ToolbarMenuSelect.tsx 中有最直观的体现默认情况下工具栏图标会跟随当前选中项的icon变化除非设置preventDynamicIcon: true当dynamicTitle为真时按钮标题会替换为当前选中项的title即title getSelectedItem(...)?.title || title如果某个工具栏项既没有title也没有icon控制台会输出告警。此外toolbar的items除了普通选项外还支持一个特殊的type: reset选项用于在菜单底部提供重置入口见 ToolbarMenuSelect.tsx 与 toolbar/types.ts。items 的两种写法items可以接受纯字符串数组如[light, dark]也可以接受MenuItem形状的对象数组。后者能呈现更丰富的 UI字段如下见 toolbar/types.ts 中ToolbarItem定义MenuItem 字段类型说明是否必填valueString选中后写入 globals 的字符串值是titleString菜单项的主文本是rightString显示在菜单项右侧的文本如国旗 emoji否iconString该项被选中时工具栏显示的图标否hideIconBoolean是否在菜单项内隐藏图标否typeitem \| reset标记该项为普通选项或重置项否消费 globals用装饰器让全局变量生效声明了theme全局变量后还需要把它接上渲染流程。推荐的方式是在装饰器中读取context.globals.theme因为装饰器对所有故事生效与 globals 的全局语义天然匹配。以 React styled-components 为例完整示例见 storybook-preview-use-global-type.md// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc. import type { Preview } from storybook/your-framework; import { ThemeProvider } from styled-components; import { MyThemes } from ../my-theme-folder/my-theme-file; const preview: Preview { decorators: [ (Story, context) { const theme MyThemes[context.globals.theme]; return ( ThemeProvider theme{theme} Story / /ThemeProvider ); }, ], }; export default preview;Vue 3 Vuetify 的写法则是把 global 值注入组件模板import { type Preview, setup } from storybook/vue3-vite; import { VApp } from vuetify/components; import { registerPlugins } from ../src/plugins; setup((app) { // Registers your apps plugins including Vuetify into Storybook registerPlugins(app); }); const preview: Preview { decorators: [ (story, context) { const theme context.globals.theme || light; return { components: { story, VApp }, template: v-app theme${theme} div classd-flex story/ /div /v-app , }; }, ], }; export default preview;Angular 可以借助componentWrapperDecorator的第二参数据globals动态绑定类名import { type Preview, componentWrapperDecorator } from storybook/angular; const preview: Preview { decorators: [ componentWrapperDecorator( (story) div [class]myTheme${story}/div, ({ globals }) { return { myTheme: globals[theme] }; }, ), ], }; export default preview;从类型层面看StoryContext中已包含globals字段见 story.ts因此装饰器内可以直接通过context.globals访问无需额外声明。源码视角globalTypes 是如何变成运行时 globals 的理解配置的底层流转有助于排查问题。整个链路位于 preview-api/modules/store 目录提取默认值getValuesFromGlobalTypes()遍历globalTypes把每个声明了defaultValue的字段收集为默认 globals见 getValuesFromGlobalTypes.ts。合并初始状态GlobalsStore.set()将globalTypes 默认值与initialGlobals合并为initialGlobals当前值globals初始等于该值见 GlobalsStore.ts。更新与过滤update()通过filterAllowedGlobals()只允许写入已声明过的 key未声明的 key 会被拒绝并告警若把某 global 更新为undefined则会回退到initialGlobals中的初始值见 GlobalsStore.ts。渲染反馈工具栏下拉组件通过useGlobals()读取当前值并调用updateGlobals()写回见 ToolbarMenuSelect.tsxglobals 变化即触发故事重渲染。对 globals 的测试也集中在 GlobalsStore.test.ts 与 globals.test.ts 中可作为理解行为边界的参考。高级用法国际化 locale 全局变量在 toolbars-and-globals.mdx 中提供了一个更复杂的示例声明locale全局变量并在菜单项右侧显示国旗。这正好演示了MenuItem对象形状的用法完整片段见 storybook-preview-locales-globaltype.md// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Preview } from storybook/your-framework; const preview: Preview { globalTypes: { locale: { description: Internationalization locale, toolbar: { icon: globe, items: [ { value: en, right: , title: English }, { value: fr, right: , title: Français }, { value: es, right: , title: Español }, { value: zh, right: , title: 中文 }, { value: kr, right: , title: 한국어 }, ], }, }, }, initialGlobals: { locale: en, }, }; export default preview;要点说明right字段会在菜单项右侧渲染文本这里是国旗 emoji一旦该选项被选中可通过装饰器读取context.globals.locale切换语言资源icon使用storybook/icons中的图标名如globe、circlehollow若某个菜单项需要icon或right就必须使用完整的MenuItem形状而不能再用纯字符串。在故事级覆盖 globalsglobalTypes/initialGlobals只能在 preview 中声明但具体的故事或组件可以通过globals注解覆盖全局值。例如让 Button 的所有故事强制使用灰色背景仅OnDark故事使用深色背景export default { title: Components/Button, globals: { backgrounds: { value: light }, }, }; export const OnDark { globals: { backgrounds: { value: dark }, }, };此时查看这些故事时对应 global 的工具栏菜单会被禁用并显示该 global 已在故事级设置的提示。从类型定义看globals注解同时存在于组件与故事层见 story.ts 与 story.ts。需要注意故事级覆盖会关闭用户在 UI 中自由探索该组合的能力因此应当适度使用——保持 globals 在故事级不设限才能让使用者交互式地尝试所有取值组合。消费 globals 的其他途径除了装饰器globals 还有两类消费场景在故事内部通过故事函数的context.globals如context.globals.locale按故事粒度读取适合少量特殊故事在插件addon中通过storybook/manager-api提供的useGlobals()钩子读取当前 globals或用updateGlobals更新并刷新 UI——例如在插件面板中展示当前激活的主题或在自定义工具栏插件中点击按钮切换值。小结通过globalTypestoolbar注解 initialGlobals可以在不编写任何插件代码的前提下为 Storybook 工作台添加可交互的全局状态切换能力。核心要点可归纳为globalTypes与initialGlobals只能配置在.storybook/preview.*toolbar.items支持纯字符串与MenuItem对象两种写法MenuItem提供value/title/right/icon等增强字段开启dynamicTitle可让按钮标题跟随选中项变化保持 UI 一致globals 的默认值合并、合法 key 过滤、更新回退等行为由 GlobalsStore.ts 负责消费 globals 的首选位置是装饰器也可在故事内或插件中按需读取与更新。如需查看完整的工具栏与 globals 教程可继续阅读 toolbars-and-globals.mdx。【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考