拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Storybook Story 级 layout 参数详解:精确控制单个 Story 在 Canvas 中的布局

Storybook Story 级 layout 参数详解精确控制单个 Story 在 Canvas 中的布局【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybooklayout参数是 Storybook 中用于控制 Story 在 Canvas 画布中定位方式的核心参数它支持在全局.storybook/preview、组件meta与单个 Story 三个层级分别配置优先级逐级提升。本文以 Story 级别的layout: centered配置为核心覆盖 Angular、React、Vue、Svelte、Web Components 等框架在 CSF 3、CSF Next 与 Svelte CSF 三种写法下的完整示例并结合仓库源码WebView.ts、base-preview-head.html剖析其底层实现帮助你在实际项目中按需控制组件在画布中的摆放位置。layout 参数是什么根据官方文档 Story layout 的说明layout是 Storybook 的参数parameter体系中的一员专门用于控制 Story 在 Canvas 标签页中的定位方式。它接受以下取值取值行为说明centered组件在 Canvas 中水平且垂直居中显示适合按钮、图标、徽章等小尺寸组件避免其在画布角落出现fullscreen组件可铺满 Canvas 的整个宽高适合页面级、全屏类组件去掉所有内边距padded在组件周围添加额外内边距默认值组件保留四周留白none移除任何布局类从源码看是特殊值用于清除当前布局效果见下文源码解析其中padded是默认值也就是说当你不设置该参数时Storybook 默认采用带内边距的布局。三个配置层级全局、组件、Storylayout参数可以在三个层级设置遵循 Storybook 参数合并机制——越具体的层级优先级越高全局层级在.storybook/preview中设置作用于项目中的所有 Story。组件层级在组件 stories 文件的meta导出即默认导出中设置作用于该组件的所有 Story。Story 层级在单个 Story 对象上设置只作用于该 Story。这是本文的核心主题也是原文档 storybook-story-layout-param.md 的代码片段所演示的场景。例如在全局配置中让所有 Story 居中// .storybook/preview.js export default { parameters: { layout: centered, }, };而在组件级别则将参数放入meta中// Button.stories.tsReact 等通用框架 import type { Meta } from storybook/your-framework; import { Button } from ./Button; const meta { component: Button, // Sets the layout parameter component wide. parameters: { layout: centered, }, } satisfies Metatypeof Button; export default meta;当需要在同一个组件的不同 Story 间采用不同布局时例如按钮组件的大部分 Story 居中展示、而其中一个全宽 Story 使用fullscreen就需要 Story 级配置它拥有最高的优先级。Story 级 layout 配置各框架完整示例以下示例均演示在单个 Story 上设置parameters: { layout: centered }文件名为Button.stories.*。CSF 3 写法AngularCSF 3// Button.stories.ts import type { Meta, StoryObj } from storybook/angular; import { Button } from ./button.component; const meta: MetaButton { component: Button, }; export default meta; type Story StoryObjButton; export const WithLayout: Story { parameters: { layout: centered, }, };React 等通用框架CSF 3JS/JSX// Button.stories.js import { Button } from ./Button; export default { component: Button, }; export const WithLayout { parameters: { layout: centered, }, };通用框架CSF 3TS/TSX// Button.stories.ts // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta, StoryObj } from storybook/your-framework; import { Button } from ./Button; const meta { component: Button, } satisfies Metatypeof Button; export default meta; type Story StoryObjtypeof meta; export const WithLayout: Story { parameters: { layout: centered, }, };SvelteCSF 3JS// Button.stories.js import Button from ./Button.svelte; export default { component: Button, }; export const WithLayout { parameters: { layout: centered, }, };SvelteCSF 3TS// Button.stories.ts // Replace your-framework with svelte-vite or sveltekit import type { Meta, StoryObj } from storybook/your-framework; import Button from ./Button.svelte; const meta { component: Button, } satisfies Metatypeof Button; export default meta; type Story StoryObjtypeof meta; export const WithLayout: Story { parameters: { layout: centered, }, };Web ComponentsCSF 3JS// Button.stories.js export default { component: demo-button, }; export const WithLayout { parameters: { layout: centered, }, };Web ComponentsCSF 3TS// Button.stories.ts import type { Meta, StoryObj } from storybook/web-components-vite; const meta: Meta { component: demo-button, }; export default meta; type Story StoryObj; export const WithLayout: Story { parameters: { layout: centered, }, };Svelte CSF 写法Svelte CSFJS!-- Button.stories.svelte -- script module import { defineMeta } from storybook/addon-svelte-csf; import Button from ./Button.svelte; const { Story } defineMeta({ component: Button, }); /script Story nameWithLayout parameters{{ layout: centered, }} /Svelte CSFTS写法与 JS 版本完全一致同样通过Story parameters{{ layout: centered }} /的方式声明。CSF Next 写法CSF Next 是 Storybook 的下一代 CSF 语法实验性通过从../.storybook/preview导入的preview实例用preview.meta()/preview.story()声明式地组织 stories。AngularCSF Next// Button.stories.ts import preview from ../.storybook/preview; import { Button } from ./button.component; const meta preview.meta({ component: Button, }); export const WithLayout meta.story({ parameters: { layout: centered, }, });ReactCSF NextTS/TSX 与 JS/JSX 写法一致// Button.stories.ts import preview from ../.storybook/preview; import { Button } from ./Button; const meta preview.meta({ component: Button, }); export const WithLayout meta.story({ parameters: { layout: centered, }, });VueCSF NextTS 与 JS 写法一致// Button.stories.ts import preview from ../.storybook/preview; import Button from ./Button.vue; const meta preview.meta({ component: Button, }); export const WithLayout meta.story({ parameters: { layout: centered, }, });Web ComponentsCSF NextTS 与 JS 写法一致// Button.stories.ts import preview from ../.storybook/preview; const meta preview.meta({ component: demo-button, }); export const WithLayout meta.story({ parameters: { layout: centered, }, });源码解析layout 参数在预览层如何生效理解了配置写法后我们来看 Storybook 内部是如何消费这个参数的。布局类映射与默认值在预览层核心文件 WebView.ts 中layout参数与 CSS 类名一一映射const layoutClassMap { centered: sb-main-centered, fullscreen: sb-main-fullscreen, padded: sb-main-padded, } as const; type Layout keyof typeof layoutClassMap | none;Layout类型除了三个合法取值外还包含none——从类型定义可见none是官方认可的清除布局特殊值。应用与校验流程applyLayout方法WebView.ts负责实际应用布局applyLayout(layout: Layout padded) { if (layout none) { document.body.classList.remove(this.currentLayoutClass!); this.currentLayoutClass null; return; } this.checkIfLayoutExists(layout); const layoutClass layoutClassMap[layout]; document.body.classList.remove(this.currentLayoutClass!); document.body.classList.add(layoutClass); this.currentLayoutClass layoutClass; }几个关键实现细节默认值padded与方法签名一致未设置layout参数时自动回退到padded这正是文档所说默认布局的来源。none的处理不添加任何布局类而是清除当前已应用的类可用于覆盖更上层配置、回到无布局样式状态。切换机制每次先移除旧类、再添加新类保证多个 Story 切换时布局不会叠加残留。非法值告警checkIfLayoutExistsWebView.ts会对未在映射表中的值通过logger.warn输出警告提示desired layout 不是合法选项可选值为centered, fullscreen, padded, none——这意味着写错参数值如center不会崩溃但会在控制台得到明确提示。调用时机在每次渲染 Story 前prepareForStoryWebView.ts都会读取story.parameters.layout并调用applyLayoutprepareForStory(story: PreparedStoryany) { this.showStory(); this.applyLayout(story.parameters.layout); // ...滚动位置与 htmlLang 处理 }由于参数在合并时已按全局 → 组件 → Story的顺序完成继承与覆盖这里拿到的story.parameters.layout已经是该 Story 最终生效的值从而实现了三级配置的优先级语义。另外值得注意的是在 Docs 模式prepareForDocsWebView.ts下Storybook 会强制applyLayout(fullscreen)让文档页内容铺满画布——这与 Story 模式下的自定义布局互不影响。对应 CSS 类定义这些布局类的实际样式定义在预览 HTML 模板 base-preview-head.html 中sb-main-centeredbase-preview-head.html将body设为display: flex; align-items: center; min-height: 100vh并把#storybook-root设为margin: auto实现水平和垂直双向居中同时保留1rem内边距与max-height: 100%防止溢出。sb-main-fullscreenbase-preview-head.htmlmargin: 0; padding: 0; display: block完全去除留白让组件占满画布。sb-main-paddedbase-preview-head.htmlpadding: 1rem的带内边距块级布局。优先级与继承关系理解 Storybook 的参数合并机制有助于避免为什么我的全局配置不生效之类的困惑全局preview中的layout提供项目级默认值组件meta中的layout覆盖全局值作用于该组件全部 Story单个 Story 上的layout覆盖组件级配置只影响该 Story。若某 Story 想显式取消继承自组件/全局的居中布局可使用layout: none清除布局类恢复到无特殊布局状态。小结layout参数是控制 Storybook Canvas 展示形态最直接的手段而 Story 级配置是其中最精细的一层。本文覆盖了三种合法取值centered/fullscreen/padded默认及特殊值none的语义在 CSF 3、CSF Next、Svelte CSF 三种语法下Angular、React、Vue、Svelte、Web Components 各框架的完整 Story 级配置示例从 WebView.ts 的layoutClassMap、applyLayout、checkIfLayoutExists到 base-preview-head.html 中 CSS 类的完整实现链路全局、组件、Story 三级参数继承与覆盖规则以及 Docs 模式强制fullscreen的特殊行为。掌握这一参数你就可以为按钮、图标等小组件一键居中为全屏页面组件铺满画布并在同一组件内按 Story 差异化控制展示布局。【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门