各位听众,大家好!今天咱们来聊聊一个前端开发神器——Storybook,这玩意儿能帮你把组件玩出花来,还能自动生成文档,简直是懒人福音,效率神器!
一、啥是Storybook?(别跟我说storybook是童话故事书!)
Storybook,可不是童话故事书,它是一个开源的 UI 组件开发工具。简单来说,它提供了一个隔离的环境,让你可以在不依赖整个应用的情况下,独立地开发、测试和展示你的 UI 组件。你可以把它想象成一个组件的“展览馆”,每个组件都有自己的“展位”,你可以随意调整灯光(props)、背景(theme),看看它们在不同场景下的表现。
二、为啥要用Storybook?(用了你就回不去了!)
用Storybook的好处那可太多了,就像用了飘柔,头发都顺滑了:
- 组件独立开发: 告别了“牵一发而动全身”的噩梦。不用启动整个应用,就可以专注地开发和调试单个组件。
- 组件文档自动化: 自动生成组件文档,再也不用手动维护那份永远滞后的文档了。
- 组件复用性提升: 清晰地展示了组件的各种状态和用法,方便团队成员理解和复用。
- 视觉测试: 方便进行视觉回归测试,确保组件在不同版本下的外观一致。
- 团队协作: 统一的组件库,方便团队成员共享和使用,避免重复造轮子。
三、Storybook怎么玩?(手把手教你!)
咱们以一个简单的React组件为例,来演示一下Storybook的用法。
3.1 安装Storybook:
首先,在一个现有的 React 项目中,或者新建一个项目,运行以下命令安装 Storybook:
npx storybook init
这个命令会自动检测你的项目类型,并安装相应的依赖。安装完成后,会生成一个 .storybook
目录,以及一些示例 stories。
3.2 创建你的第一个 Story:
假设我们有一个简单的按钮组件 Button.jsx
:
// Button.jsx
import React from 'react';
import PropTypes from 'prop-types';
const Button = ({ primary, backgroundColor, size, label, onClick }) => {
const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
return (
<button
type="button"
className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}
style={backgroundColor ? { backgroundColor } : {}}
onClick={onClick}
>
{label}
</button>
);
};
Button.propTypes = {
primary: PropTypes.bool,
backgroundColor: PropTypes.string,
size: PropTypes.oneOf(['small', 'medium', 'large']),
label: PropTypes.string.isRequired,
onClick: PropTypes.func,
};
Button.defaultProps = {
backgroundColor: null,
primary: false,
size: 'medium',
onClick: undefined,
};
export default Button;
然后,我们创建一个对应的 Story 文件 Button.stories.jsx
:
// Button.stories.jsx
import React from 'react';
import Button from './Button';
export default {
title: 'Example/Button',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
onClick: { action: 'clicked' },
},
};
const Template = (args) => <Button {...args} />;
export const Primary = Template.bind({});
Primary.args = {
primary: true,
label: 'Primary Button',
};
export const Secondary = Template.bind({});
Secondary.args = {
label: 'Secondary Button',
};
export const Large = Template.bind({});
Large.args = {
size: 'large',
label: 'Large Button',
};
export const Small = Template.bind({});
Small.args = {
size: 'small',
label: 'Small Button',
};
代码解释:
title
: 定义了 Story 在 Storybook 导航栏中的路径。component
: 指定了 Story 对应的组件。argTypes
: 定义了组件的 props 以及它们的控制方式。control: 'color'
表示 backgroundColor 可以在 Storybook 中通过颜色选择器进行调整。onClick: { action: 'clicked' }
表示点击事件会被 Storybook 记录。Template
: 一个函数,用于渲染组件。Primary
,Secondary
,Large
,Small
: 不同的 Story,分别展示了按钮在不同状态下的表现。args
对象定义了每个 Story 的 props 值。
3.3 运行Storybook:
在项目根目录下运行以下命令启动 Storybook:
npm run storybook
或者
yarn storybook
Storybook 会在浏览器中打开,你可以看到你的按钮组件,以及各种 Story。
四、Storybook进阶玩法:(让你的组件更上一层楼!)
4.1 使用 Addons:
Storybook 的强大之处在于它的 Addons。 Addons 可以扩展 Storybook 的功能,比如:
@storybook/addon-knobs
: 允许你在 Storybook 中动态修改组件的 props。 (已经过时,推荐使用@storybook/addon-essentials
自带的 Controls)@storybook/addon-viewport
: 模拟不同的设备屏幕尺寸。@storybook/addon-a11y
: 检查组件的可访问性。@storybook/addon-interactions
: 用于测试组件的交互行为。
安装 Addons:
npm install @storybook/addon-viewport @storybook/addon-a11y @storybook/addon-interactions --save-dev
配置 Addons:
在 .storybook/main.js
文件中配置 Addons:
// .storybook/main.js
module.exports = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-viewport',
'@storybook/addon-a11y',
'@storybook/addon-interactions',
'@storybook/addon-links',
],
framework: '@storybook/react',
core: {
builder: '@storybook/builder-webpack5',
},
};
4.2 使用 Controls (替代 Knobs):
Controls
是 @storybook/addon-essentials
自带的功能,可以让你在 Storybook 中动态修改组件的 props,比 Knobs 更强大,更易用。
在你的 Story 文件中,通过 argTypes
来定义组件的 props 以及它们的控制方式:
// Button.stories.jsx
import React from 'react';
import Button from './Button';
export default {
title: 'Example/Button',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
label: { control: 'text' },
size: { control: { type: 'select', options: ['small', 'medium', 'large'] } },
onClick: { action: 'clicked' },
},
};
const Template = (args) => <Button {...args} />;
export const Primary = Template.bind({});
Primary.args = {
primary: true,
label: 'Primary Button',
};
export const Secondary = Template.bind({});
Secondary.args = {
label: 'Secondary Button',
};
export const Large = Template.bind({});
Large.args = {
size: 'large',
label: 'Large Button',
};
export const Small = Template.bind({});
Small.args = {
size: 'small',
label: 'Small Button',
};
代码解释:
control: 'color'
: 使用颜色选择器控制 backgroundColor。control: 'text'
: 使用文本输入框控制 label。control: { type: 'select', options: ['small', 'medium', 'large'] }
: 使用下拉选择框控制 size,并指定可选的值。control: 'boolean'
: 使用开关控制 boolean 类型的 prop。control: { type: 'number', min: 0, max: 100, step: 1 }
: 使用数字输入框控制 number 类型的 prop,并指定最小值、最大值和步长。
4.3 使用 Interactions Addon进行交互测试:
@storybook/addon-interactions
可以让你在 Storybook 中模拟用户交互,并对组件进行交互测试。
首先,安装这个addon:
npm install @storybook/addon-interactions --save-dev
然后在你的story文件中,使用play
函数来模拟用户交互和进行断言。
// Button.stories.jsx
import React from 'react';
import Button from './Button';
import { within, userEvent } from '@storybook/testing-library';
import { expect } from '@storybook/jest';
export default {
title: 'Example/Button',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
label: { control: 'text' },
size: { control: { type: 'select', options: ['small', 'medium', 'large'] } },
onClick: { action: 'clicked' },
},
};
const Template = (args) => <Button {...args} />;
export const Primary = Template.bind({});
Primary.args = {
primary: true,
label: 'Primary Button',
};
Primary.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
const button = await canvas.getByRole('button', { name: /Primary Button/i });
await userEvent.click(button);
expect(button).toBeVisible(); // 简单的断言,确保按钮是可见的
};
export const Secondary = Template.bind({});
Secondary.args = {
label: 'Secondary Button',
};
export const Large = Template.bind({});
Large.args = {
size: 'large',
label: 'Large Button',
};
export const Small = Template.bind({});
Small.args = {
size: 'small',
label: 'Small Button',
};
在这个例子中,Primary.play
函数模拟了用户点击 Primary Button
的操作,并使用 expect
断言按钮是可见的。 当你在 Storybook 中查看 Primary
这个 story 时, Storybook 会自动执行 play
函数,并显示测试结果。
4.4 使用 DocsPage:
Storybook 默认提供 DocsPage
addon, 可以根据你的组件和 story 自动生成文档。 你需要在.storybook/main.js
中确保@storybook/addon-docs
在addons列表中. 并且,你可以在 story 文件中添加组件的描述和使用示例。
// Button.stories.jsx
import React from 'react';
import Button from './Button';
export default {
title: 'Example/Button',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
label: { control: 'text' },
size: { control: { type: 'select', options: ['small', 'medium', 'large'] } },
onClick: { action: 'clicked' },
},
parameters: {
docs: {
description: {
component: 'A simple button component.',
},
},
},
};
const Template = (args) => <Button {...args} />;
export const Primary = Template.bind({});
Primary.args = {
primary: true,
label: 'Primary Button',
};
Primary.parameters = {
docs: {
description: {
story: 'The primary button style.',
},
},
};
export const Secondary = Template.bind({});
Secondary.args = {
label: 'Secondary Button',
};
export const Large = Template.bind({});
Large.args = {
size: 'large',
label: 'Large Button',
};
export const Small = Template.bind({});
Small.args = {
size: 'small',
label: 'Small Button',
};
在上面的例子中,我们使用 parameters.docs.description.component
添加了组件的描述,使用 parameters.docs.description.story
添加了每个 story 的描述。 这些描述会显示在 Storybook 的 Docs 页面中。
五、Storybook的架构和原理(了解底层才能玩得更溜!)
Storybook 的核心架构包括以下几个部分:
- Core: Storybook 的核心引擎,负责加载、解析和渲染 stories。
- Addons API: 允许开发者扩展 Storybook 的功能。
- UI: Storybook 的用户界面,用于展示组件和控制 props。
- Builders: 用于构建 Storybook 的静态资源,支持 Webpack、Vite 等构建工具。
Storybook 的工作原理大致如下:
- 加载 Stories: Storybook 会扫描项目中的
.stories.js
或.stories.jsx
文件,加载所有的 stories。 - 解析 Stories: Storybook 会解析每个 story,提取组件、props 和其他配置信息。
- 渲染组件: Storybook 会根据 story 的配置,渲染组件,并在 UI 中展示。
- 交互控制: 用户可以通过 Storybook 的 UI 修改组件的 props,触发事件,并查看组件的实时更新。
- 生成文档: Storybook 可以根据组件和 story 的信息,自动生成组件文档。
六、Storybook与其他工具的比较(知己知彼,百战不殆!)
工具 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
Storybook | 组件独立开发、组件文档自动化、组件复用性提升、视觉测试、团队协作、丰富的 Addons、强大的 Controls、交互测试。 | 需要一定的学习成本、配置相对复杂 | UI 组件库开发、设计系统搭建、组件文档生成、视觉回归测试、团队协作。 |
Styleguidist | 自动生成组件文档、支持 Markdown 编写文档、配置简单。 | 功能相对简单、扩展性较差、不支持交互测试。 | 简单的组件文档生成、不需要复杂配置的场景。 |
Bit | 组件共享、组件版本控制、组件依赖管理。 | 学习成本较高、配置复杂、需要搭建 Bit 服务器。 | 组件共享、组件版本控制、跨项目组件复用。 |
Docz | 基于 MDX 的文档生成工具、支持 React 组件、配置简单。 | 功能相对简单、扩展性较差。 | 简单的组件文档生成、基于 MDX 的文档编写。 |
七、总结(希望你听完能有所收获!)
Storybook 是一款强大的 UI 组件开发工具,可以帮助你提高组件开发的效率、提升组件的复用性、自动化组件文档的生成、方便进行视觉测试、促进团队协作。 虽然它需要一定的学习成本和配置,但一旦掌握,你就能体会到它的强大之处。 希望通过今天的讲座,你能对 Storybook 有更深入的了解,并在实际项目中灵活运用,让你的组件开发更上一层楼!
好了,今天的讲座就到这里,感谢大家的收听! 如果大家还有什么问题,可以随时提问。下次有机会再和大家分享更多有趣的技术知识!