Storybook 是一个 ui 组件开发管理的工具,我们可以通过 story 独立创建组件,并且每个组件都有一个独立开发调试环境。Storybook 是运行在主应用程序之外,不依赖于项目,因此我们不必担心开发环境、依赖等问题导致不能开发组件。
Storybook 支持多个主流框架(React, Vue, Angular, Mithril, Ember)等,由于目前笔者使用的是 react 技术栈,本文将介绍 react 项目如何配置使用 Storybook。
一. 操作指南
- 首先,安装@storybook/react,react, react-dom, babel-core 等项目所需基础库。在 package.json 文件中添加 “storybook”: “start-storybook -p 9001 -c .storybook”
- 新建文件,先看下项目目录结构

- .storybook 文件夹存放 storybook 配置,及插件文件。
- src/components 存放 UI 组件。
- src/markdown 存放组件显示的文档等介绍。
- src/stories 存放 story,story 可绑定相应的组件,一个组件可以有多个不同状态的 story。
- 编写 story
- 添加 storybook 配置文件- .config 配置文件1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26import { configure, addDecorator } from '@storybook/react'; 
 import { withOptions } from '@storybook/addon-options';
 import { withNotes } from '@storybook/addon-notes';
 import { themes } from '@storybook/components';
 // 全局加载装饰器
 // addDecorator(story => <div style={{ textAlign: 'center' }}>{story()}</div>);
 addDecorator(
 withOptions({
 // name: 'Foo',
 // theme: themes.dark
 showSearchBox: false,
 showAddonsPanel: true,
 addonPanelInRight : true,
 enableShortcuts : true,
 })
 )
 addDecorator(withNotes);
 /**
 * 动态加载所有stories
 */
 const req = require.context('../src/stories', true, /\.stories\.js$/);
 function loadStories() {
 req.keys().forEach(fileName => req(fileName));
 }
 configure(loadStories, module);
 
- .config 配置文件
这里为了动态加载 stories,Storybook 使用了 Webpack 的 require.context 动态加载模块。
- 添加 UI 组件(src/components/circle) - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15- import React from 'react' 
 import './style.scss'
 export function Circle (props) {
 const defaultClass = 'circle_default';
 const { className, ...other } = props;
 return (
 <div
 className={`${defaultClass} ${className} `}
 {...other}
 >
 {props.children || ''}
 </div>
 )
 }
- 添加 story(src/stories/circle.stories.js) - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76- import React from 'react'; 
 import { storiesOf } from '@storybook/react';
 import { action } from '@storybook/addon-actions';
 import { withKnobs, text, boolean, number, object } from '@storybook/addon-knobs';
 import { Circle } from '../components/circle';
 import '../components/circle/circle-color.scss';
 import circleText from '../markdown/circle.md';
 const stories = storiesOf('Circle', module);
 // 动态修改react组件属性(测试)
 // 可在config文件中全局配置
 stories.addDecorator(withKnobs);
 stories.add('圆点', () => (
 <div>
 <div>
 <Circle className='status_running' onClick={action('clicked')}></Circle> 
 运行中
 </div>
 <div>
 <Circle className='status_finished'></Circle> 
 成功
 </div>
 <div>
 <Circle className='status_stoped'></Circle> 
 取消
 </div>
 <div>
 <Circle className='status_run_fail'></Circle> 
 运行失败
 </div>
 <div>
 <Circle className='status_submitting'></Circle> 
 提交中
 </div>
 <div>
 <Circle className='status_submit_failed'></Circle> 
 提交失败
 </div>
 <div>
 <Circle className='status_submit_failed'></Circle> 
 上游失败
 </div>
 <div>
 <Circle className='status_frozen'></Circle> 
 冻结
 </div>
 <div>
 <Circle className='status_killed'></Circle> 
 已停止
 </div>
 <div>
 <Circle className='status_restarting'></Circle> 
 重试中
 </div>
 <div>
 <Circle className='status_wait_submit'></Circle> 
 等待提交
 </div>
 </div>
 ), {
 notes: {
 markdown: circleText
 }
 });
 stories.add('动态修改style', () =>{
 const groupId = 'circle';
 const defaultStyle = {
 background: 'black'
 }
 const style = object('Style', defaultStyle, groupId);
 return <Circle style={style} ></Circle>
 }
 )
注意:
1. storybook 插件都需要在 ./stroybook/addons.js 中注册才能使用,注册完之后需要重新运行项目。
2. 这里有一个问题,在引入 markdown 作为组件文档时,其中表格渲染 border 无法显示。
3. storybook 内部集成的 webpack 不支持 scss 类型文件。需要自定义 webpack,这里我们在原来的配置基础上实现。
| 1 | const path = require("path"); | 
npm run storybook 查看效果

二. 插件
storybook 的插件有许多,基本上有两种类型(装饰器 Decorators 和原生插件 Native Addons)
Decorators 通过封装 react 组件实现,比如 storybook-router。
Native Addons 主要是以面板的形式注入,便于管理使用组件,比如 addon-actions 等。
本文主要介绍几个常用的 addons,目前项目中使用到的 addons 有:
| 1 | import '@storybook/addon-storysource/register'; | 
1. addon-storysource
此插件主要是在插件面板中显示 story 源代码

安装插件之后需要在 webpack 中定义,让其在每个 story 都生成一个装饰者调用。
| 1 | module.exports = function (baseConfig, env, defaultConfig) { | 
并且可以在 options 选项中定义 printWidth 等更多优化配置格式化面板。
2. addon-knobs
| 1 | import React from 'react'; | 
我们在这个 story 中定义了 style、visible、children 三个动态变量传入 SlidePanel 组件,其变量类型分别对应的是 boolean、object、text。在 knob 中还可以导入许多的类型约束(number, color, array)等。

注意:
在定义动态变量时,可以通过 groupId 来分类不同组件的变量,在选项卡中将会以 groupId 在组中过滤,没有参入 groupId,将会自动分类到 All 组中。
3. addon-actions
actions 可以用于显示 storybook 事件处理程序接收的数据(多个事件触发可以写成对象形式)
| 1 | import React from 'react'; | 
4. addon-notes
可以在面板中添加 story 注释文本信息。
addon-notes 只允许在面板中显示信息,有时候不方便我们查看组件 api 等详细信息。如果我们想要在组件旁边显示用法以及其他类型的文档介绍等信息,可以安装 addon-info(组件文档管理必备)。
storybook 提供了许多 addons。
- storybook-state: 添加 state 面板,展示或更新 state,重绘视图。
- storyShots: 快照测试。
- storybook-readme: 将 markdown 导入为 story 等。
更多插件介绍详情官网
三. 写在后面
这篇文章简单介绍了如何基础使用 storybook 工具集成显示 ui 组件,总体感觉是学习成本不算高。为了后期有便于更好的维护组件,有信心的提交代码,那测试功能必不可少。并且目前不能直接在 story 中修改 react 组件 state。下篇文章我们将集成 redux 便于管理数据,详细叙述 storybook 是如何利用基于 jest 的 addons 进行一系列的自动化测试以及手动测试。