ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

一次声明,六框架通用:Storybook Button 组件 Props 声明与 JSDoc 注释实战指南

一次声明,六框架通用:Storybook Button 组件 Props 声明与 JSDoc 注释实战指南 一次声明六框架通用Storybook Button 组件 Props 声明与 JSDoc 注释实战指南【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook在 Storybook 跨框架开发里最容易被低估的一件事是组件的 Props 声明本身就是 Docs 面板、Controls 控件、乃至自动化测试的数据源。你写下的类型、默认值和注释会在 Storybook 构建时被打成一份叫 argTypes 的结构化描述直接决定面板长什么样。本文以官方文档仓库 docs/_snippets/button-component-with-proptypes.md 中的跨框架代码示例为素材拆解同一个 Button 在 React、Angular、Vue 3、Svelte 与 Web ComponentsLit下的声明写法以及这些声明如何驱动 Storybook 自动推导 argTypes。 一条链路讲透从 React TS 的 Props 声明到 argTypes 推导先看整条链路中最完整的一环React 的 TypeScript 版本。这个示例声明了一个布尔开关isDisabled和一段展示文本contentexport interface ButtonProps { /** * Checks if the button should be disabled */ isDisabled: boolean; /** The display content of the button */ content: string; } export const Button: React.FCButtonProps ({ isDisabled false, content }) { return ( button typebutton disabled{isDisabled} {content} /button ); };两个字段都没写?即均为必填字段正上方的 JSDoc 是描述文本的唯一来源解构处的isDisabled false与content 是运行时默认值docgen 会把它们记为 argTypes 的defaultValueReact.FCButtonProps这个泛型标注是 docgen 工具链识别函数组件 Props 形态的入口。组件上那些注释到底给谁看答案是给 Storybook 自己看。构建时各框架的 docgen 工具会解析源码产出形如 docs/_snippets/storybook-generated-argtypes.md 所示的结构const argTypes { label: { name: label, type: { name: string, required: false }, defaultValue: Hello, description: demo description, table: { type: { summary: string }, defaultValue: { summary: Hello }, }, control: { type: text, }, }, };type.name决定控件形态boolean渲染成开关string渲染成文本框description显示在 Docs 的 ArgsTable 与 Controls 面板中table.defaultValue是默认值的汇总展示缺省留空。在 React 这条链路上负责读注释的工具取决于你的构建方式Vite 框架 code/frameworks/react-vite/package.json 依赖react-docgen与joshwooding/vite-plugin-react-docgen-typescript并在 code/frameworks/react-vite/src/plugins 下自定义了 docgen handler 与 resolverWebpack 侧则由 code/presets/react-webpack/package.json 引入storybook/react-docgen-typescript-plugin。docgen 工具链横向对照每个框架的注释被谁解析不同框架读注释的方式差异很大但目标一致把源码里的元信息转成 argTypes。Angularcode/frameworks/angular/package.json 依赖storybook/angular-compodoc执行 Compodocbuilder 选项可在 code/frameworks/angular/build-schema.json 中通过compodoc与compodocArgs调整Angular-Vite 则内置了自己的 docgen workercode/frameworks/angular-vite/package.json 导出的./internal/docgen-workerVue 3渲染器依赖vue-docgen-api通过 code/renderers/vue3/src/docgen/build-docgen.ts 与内部docgen-worker见 code/renderers/vue3/package.json把组件__docgenInfo转换为 argTypesSvelte由storybook/addon-svelte-csf的defineMeta读取组件注释生成元信息Web Components / Lit直接解析类上方的 JSDoc 块prop、summary、tag以及property()装饰器。工具链决定了你的注释写在哪个位置才有效React 写在 props 成员上方Angular 写在Input字段上方Lit 写在类声明上方。放错位置的注释不会报错只会安静地消失。六大框架的 Props 声明矩阵先把结论压缩成一张表再看每段代码的要点框架 / 变体声明位置docgen 工具链类型表达方式必填表达方式描述文本来源React (JS)Button.propTypesreact-docgenPropTypes.bool/string.isRequired后缀属性上方 JSDocReact (TS)ButtonPropsinterfacereact-docgen-typescriptTS 类型 React.FC泛型字段省略?字段上方 JSDocAngular类中Input()字段Compodoc字段 TS 类型requiredJSDoc 标记字段上方 JSDocVue 3 (JS/TS)props选项vue-docgen-api运行时type: Boolean/Stringrequired: trueprop 上方注释Svelteexport let变量addon-svelte-csfSvelte 编译器推导required标记变量上方 JSDocWeb Components (JS/TS)static get properties/property()JSDoc 解析type: String/Boolean或 Lit 装饰器 TS 类型默认值约定类上方propJSDocReactJS 变体用 PropTypes 补齐运行期类型TS 版本已在上一节讲过这里补上 JavaScript 变体组件本身是纯函数类型元信息靠prop-types包在运行期声明import React from react; import PropTypes from prop-types; export function Button({ isDisabled, content }) { return ( button typebutton disabled{isDisabled} {content} /button ); } Button.propTypes { /** Checks if the button should be disabled */ isDisabled: PropTypes.bool.isRequired, /** The display content of the button */ content: PropTypes.string.isRequired, };.isRequired使属性缺失时 PropTypes 在开发环境控制台告警这是 JS 版本表达必填的唯一手段注释块紧贴属性名书写react-docgen 会将其提取为description此变体未提供默认值仅要求调用方传入与 TS 变体的解构默认值形成对照同一组件两种声明策略argTypes 里的defaultValue有无不同。AngularInput 装饰器加字段注释import { Component, Input } from angular/core; Component({ selector: my-button, template: button typebutton [disabled]isDisabled {{ content }} /button, styleUrls: [./button.css], }) export class ButtonComponent { /** * Checks if the button should be disabled */ Input() isDisabled: boolean; /** The display content of the button */ Input() content: string; }selector: my-button是组件标签名Angular 要求自定义元素至少两个词避免与原生button冲突[disabled]isDisabled属性绑定布尔开关{{ content }}插值渲染文本两个输入均未赋初值若希望组件可独立渲染建议写成isDisabled false这是 Angular 表达可选且有默认值的常规写法。Vue 3props 对象的三要素与 TS 变体Options API 在props中集中声明type、default、requiredtemplate button typebutton :disabledisDisabled{{ label }}/button /template script import { reactive } from vue; export default { name: button, props: { /** * Checks if the button should be disabled */ isDisabled: { type: Boolean, default: false, required: true, }, /** * The display label of the button */ label: { type: String, default: One, required: true, }, }, setup(props) { props reactive(props); return { /** * What will be returned here will available to the component * Functions referenced here will act like methods */ }; // }, }; /scriptisDisabled与label都同时写了default与required: true——这种并存写法本身值得商榷见后文的踩坑清单setup里把 props 交给reactive包装、返回空对象只是占位示意未真正暴露任何绑定TS 变体用defineComponent包住选项对象script langtsprops获得完整类型推导setup(props)的参数自带类型提示。关键差异在于TS 变体的isDisabled移除了required: true、只保留default: false两个变体对同一属性是否必填给出了不同答案。Svelteexport let 声明属性script /** * A Button Component * component */ /** * Disable the button * required */ export let disabled false; /** * Button content * required */ export let content ; script/ button typebutton {disabled}{content}/buttonexport let disabled false声明布尔属性并带默认值模板里的{disabled}是disabled{disabled}的简写required与component标记供 Svelte CSF / docgen 工具解析出结构化信息注意属性名是disabled而非其他框架的isDisabled跨框架对照时要留心命名漂移片段中的script/在真实 Svelte 组件里必须闭合为/script否则编译器直接报错。Web Components (Lit)JSDoc prop 与 property 装饰器JS 版本通过static get properties()声明可观察属性元信息写在类上方import { LitElement, html } from lit; /** * prop {string} content - The display label of the button * prop {boolean} isDisabled - Checks if the button should be disabled * summary This is a custom button element * tag custom-button */ export class CustomButton extends LitElement { static get properties() { return { content: { type: String }, isDisabled: { type: Boolean }, }; } constructor() { super(); this.content One; this.isDisabled false; } render() { return html button typebutton ?disabled${this.isDisabled}${this.content}/button ; } } customElements.define(custom-button, CustomButton);properties里的type决定属性反射与类型转换规则Boolean属性用?disabled布尔属性绑定语法渲染构造函数赋默认值content One、isDisabled falsetag custom-button与customElements.define(custom-button, ...)共同确定元素注册名。TS 变体改用装饰器声明压缩成两行字段import { LitElement, html } from lit; import { customElement, property } from lit/decorators.js; /** * prop {string} content - The display label of the button * prop {boolean} isDisabled - Checks if the button should be disabled * summary This is a custom button element * tag custom-button */ customElement(custom-button) export class CustomButton extends LitElement { property() content?: string One; property() isDisabled?: boolean false; render() { return html button typebutton ?disabled${this.isDisabled}${this.content}/button ; } }customElement(custom-button)同时完成类装饰与元素注册不再需要手写customElements.define字段的?可选标记配合初值表达非必填但有默认值类上方的 JSDoc 块在两个变体中保持一致docgen 都能解析出同样的prop信息。 元信息的三个来源类型、默认值与注释漏写会怎样所有框架的声明都可以拆成三份数据漏掉任何一份面板都会缺一角类型布尔进开关、字符串进文本框、枚举进下拉。类型缺失时 Controls 无法匹配专用控件只能退回通用文本输入交互体验与参数校验都会打折扣默认值进入 argTypes 的defaultValue与table.defaultValue。漏写时 ArgsTable 的 Default 列留空读者无法从文档判断不传会怎样注释成为description出现在 ArgsTable 与 Controls 中。漏写不报错但 Docs 页面对每个属性只剩名字文档价值归零。三种元信息在各框架中的住址见上表React 的注释写在 props 成员上方、Angular 写在Input字段上方、Vue 写在 prop 上方、Svelte 写在变量上方、Lit 写在类上方。统一记忆口径就一句注释必须紧贴它描述的那个声明成员且放在工具链实际扫描的位置。跨框架踩坑清单命名漂移、required 并存与两处隐藏陷阱对照同一 Button 在五个框架中的写法有几处不一致是真实项目里最容易踩的字段命名不统一React、Angular、Lit 用contentVue 用labelSvelte 把禁用属性叫disabled其余框架叫isDisabled。跨框架参考同一段文档时args 的键可能对不上复制粘贴前先核对required 与 default 并存Vue JS 变体给isDisabled同时写了default: false和required: true而 TS 变体只留default。必填与有默认值语义上冲突实际项目二者取其一即可Svelte 脚本闭合片段中的script/需修正为/script这是示例文件的笔误编译器会拒绝未闭合的脚本块Angular 双词 selector本示例的my-button遵循了 Angular自定义元素至少两个词的约束而同仓库 docs/_snippets/button-implementation.md 中的 Angular 示例用了单词button真实项目请以双词为准Web Components 的 meta 写法特殊storybook 的 meta 中组件名是字符串如 button-story-matching-argtypes.md 中的component: demo-button需与tag/customElements.define的注册名对应Vue 单字组件名name: button会触发vue/multi-word-component-namesESLint 规则仓库其他片段用行内注释禁用该规则处理。 下一站用 meta 关联组件走向 Story声明完成后只需在Button.stories文件的 meta 里用component把组件接进 StorybookargTypes 推导即自动生效// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc. import type { Meta } from storybook/your-framework; import { Button } from ./Button; const meta { component: Button, parameters: { actions: { argTypesRegex: ^on.* } }, } satisfies Metatypeof Button; export default meta;component: Button告诉 docgen 解析哪个组件Svelte 侧通过defineMeta传入Web Components 侧传字符串标签名argTypesRegex: ^on.*把以on开头的属性自动映射为 Actions 面板记录本示例的isDisabled/content不涉及事件但组件一旦加入onClick这类属性就会立即生效写完 meta 即可进入 Story 编写完整跨框架的 meta 示例见 docs/_snippets/button-story-matching-argtypes.mdargs 用法见 docs/writing-stories/args.mdx 与 docs/get-started/whats-a-story.mdx。回到开头的命题在 Storybook 的工作流里写组件与写文档从来不是两件事。类型写准Controls 才有对的控件默认值给全ArgsTable 的 Default 列才有内容注释贴紧声明Docs 才有人能看懂。把这一套习惯统一到你团队的每个框架里组件工作台——构建、文档、测试——才能真正做到开箱即用。【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表