前言
为了晋升团队前端工作效率,打造一套团队 UI 库是有一个无效的办法。既能够缩小重复劳动,又能够进步组件的复用率与统一性。
创立了团队 UI 库后,就很有必要搭建一个动态文档网站,用于标准 UI 库的开发扩大以及标准应用。毕竟这货色不是你一个人开发的,也不是面向你一个人用的,有手册能够查,当然比每天都去问开发人员或者本人摸索来的快。
以前是比拟趋向于 Docz 这种动态文档生成插件,Docz 的特色是零配置、简略、疾速,它应用 Markdown 语法的扩大 MDX(在 Markdown 里引入 React 组件并渲染出组件)来书写文档,对于相熟 Markdown 的开发者是能够间接上手的。
然而相似于 Docz 这种在曾经满足不了团队的需要了,我想要的不仅仅是一个文档手册汇合,我还想要在线调试,实时查看组件成果。这时候就有了 Storybook,Storybook 是一个 UI 开发环境,容许开发者设置独自的开发工作、文档以及测试。
如何在 React 中引入 Storybook
1、首先创立一个 React + Storybook 我的项目。
npx create-react-app myapp --template typescript // 创立 React 我的项目 v17.02
npx sb init // 结构成 Storybook 我的项目
结构完后的文件夹次要有如下的扭转:
├── .storybook
│ │── main.js // 主文件
│ └── preview.js // 预览设置文件
│
├─ src
│ └── stories
│ │── assets // 动态资源文件夹
│ │── button.css // 按钮款式文件
│ │── Button.tsx // 按钮主文件
│ │── Button.stories.tsx // 按钮文档页面
│ │── Introduction.stories.mdx // 欢送介绍页面,间接应用 mdx 文件, 相似 Docz
│ └── .....
因为这个目录构造是主动生成的,对于咱们当前 UI 治理不太不便,所以咱们略微将文件目录再略微革新下 src 目录构造。
在 src 下新建一个 compnent 文件夹,而后其中再以组件名文件夹分类,方便管理,如下:
├─ src
│ │──component
│ │ │── style // 款式文件
│ │ │ │── button.scss
│ │ │ │── index.scss
│ │ │ └── ...
│ │ │── button
│ │ │ │── button.tsx
│ │ │ │── Button.stories.tsx
│ │ └── ... // 参考上述文件夹
│ └── stories
│ │── assets // 动态资源文件夹
│ │── Introduction.stories.mdx // 欢送介绍页面,间接应用 mdx 文件, 相似 Docz
│ └── .....
2、main.js
因为批改了文件目录机构,所以咱们也要对应的批改 main.js 的文件匹配机制。
const path = require('path');
module.exports = {
// 应用 scss, 应用前记得装置对应的 loader
webpackFinal: async (config, { configType}) => {
config.module.rules.push({
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
include: path.resolve(__dirname, '../'),
});
// Return the altered config
return config;
},
stories: [
'../src/**/*.stories.mdx',
'../src/component/**/*.stories.@(js|jsx|ts|tsx)'
],
addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
};
其中次要是 stories 和 addons,更多的配置项能够查看 StoryBook Main Config。stories:用来形容你的故事绝对于配置文件的地位,从默认的配置能够看出格局为 '*.stories.@(js|jsx|ts|tsx)';
addons: 用来形容你要引入的 storybook 插件。webpackFinal:自定义 webpack 配置。
3、preview.js
import '../src/component/style/index.scss'; // 引入全局款式文件
import {configure} from '@storybook/react';
// 排列目录的程序
const loaderFn = () => {
const allExports = [require('../src/stories/Introduction.stories.mdx'),
require(`../src/component/button/button.stories.tsx`),
];
return allExports;
};
configure(loaderFn, module);
export const parameters = {
layout: 'centered', // canvas 页面示范元素地位居中
actions: {argTypesRegex: '^on[A-Z].*' },
controls: {
expanded: true, //canvas 页面显示形容文档的形容,类型,初始值
matchers: {color: /(background|color)$/i,
date: /Date$/,
},
},
};
次要是自定义左侧导航栏的程序,还有一些页面元素的布局和款式引入。
4、组件故事模式
在应用 storyBook 接触最多的就是 Component Story Format(CSF),这是应用了 ES6 提供的 module 编写的形式,咱们能够看下一个我编写的例子,去更好的了解这种模式。
import {Meta, Story} from '@storybook/react';
import {Button as Component, ButtonProps} from './button';
import {ButtonGroup} from '../button-group/button-group';
export default {
title: 'Component/Base/Button',
component: Component,
argTypes: {
showGroup: {
description: '是否显示按钮组,仅供测试应用,非正式属性',
defaultValue: false,
control: {type: 'boolean',},
table: {category: 'Test',},
},
//button
type: {
description: '类型',
defaultValue: 'default',
control: {
type: 'select',
options: ['default', 'primary', 'success', 'warning', 'danger', 'text'],
},
table: {
category: 'Button',
type: {summary: 'default | primary | success | warning | danger | text'},
},
},
size: {
description: '尺寸',
defaultValue: 'medium',
control: {
type: 'select',
options: ['mini', 'small', 'medium', 'large', 'big', 'huge'],
},
table: {
category: 'Button',
type: {summary: 'mini | small | medium | large | big | huge'},
},
},
prefixIcon: {
description: '前置图标',
control: {type: 'text',},
table: {category: 'Button',},
},
sufixIcon: {
description: '后置图标',
control: {type: 'text',},
table: {category: 'Button',},
},
color: {
description: '色彩',
control: {type: 'color',},
table: {category: 'Button',},
},
textColor: {
description: '文本色彩',
control: {type: 'color',},
table: {category: 'Button',},
},
nativeType: {
description: '按钮原生类型, 可参考 <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type">HTML 规范 </a>',
defaultValue: 'button',
control: {
type: 'select',
options: ['submit', 'button', 'reset'],
},
table: {
category: 'Button',
type: {summary: "submit | button | reset"},
},
},
block: {
description: '是否为块元素',
control: {type: 'boolean',},
table: {category: 'Button',},
},
disabled: {
description: '是否禁用',
control: {type: 'boolean',},
table: {category: 'Button',},
},
plain: {
description: '是否开启幽灵按钮',
control: {type: 'boolean',},
table: {category: 'Button',},
},
round: {
description: '是否开启圆角',
control: {type: 'boolean',},
table: {category: 'Button',},
},
loading: {
description: '是否开启期待动效',
table: {category: 'Button',},
},
to: {
description: '跳转地址, 测试用例只反对文本输出',
control: {type: 'text',},
table: {category: 'Button',},
},
onClick: {
description: '点击事件,返回 Event',
control: {type: null,},
table: {category: 'Button',},
},
//ButtonGroup
direction: {
description: '方向',
defaultValue: 'horizontal',
control: {
type: 'select',
options: ['horizontal', 'vertical'],
},
table: {category: 'ButtonGroup',},
},
//hidden
style: {
table: {disable: true,},
},
children: {
table: {disable: true,},
},
className: {
table: {disable: true,},
},
},
args: {
showGroup: false,
children: 'Preview',
},
} as Meta;
export const Button = (args: any) => {const { showGroup, direction, ...other} = args;
if (showGroup) {
return (<ButtonGroup direction={direction}>
<Component {...other}>PreView</Component>
<Component {...other}>Next</Component>
</ButtonGroup>
);
} else {return <Component {...other}></Component>;
}
};
export default 定义了组件的相干配置,其中别离为:
title:导航栏层级,用 ’/’ 号分隔开,而且 title 不能反复;
component:组件理论元素;
argTypes:文档形容项,默认会显示组件 props 的入参项,也能够自定减少或者重写,具体配置上面详解。
argTypes 配置通过一个例子解释比拟容易:
type: { // 字段名为 type
description: '类型', // 属性形容
defaultValue: 'default',// 开发环境默认值
control: {type: 'select', // 文档控制器类型 text(文本),select(抉择)... 依据理论状况定义
options: ['default', 'primary', 'success', 'warning', 'danger', 'text'], // 选项内容
},
table: {
category: 'Button', // 定义形容分类,可多个组件联结开发区分应用
type: {summary: 'default | primary | success | warning | danger | text'}, // 字段属性类型重写
defaultValue:{summary:'default'} // 文档形容显示的默认值
},
},
实际效果如下:
每个 export const 定义侧边栏子菜单以及相干的文档,例子中是有两个组件的联结调试,能够在 argTypes 李减少一个 showGroup 字段,显示单个按钮还是按钮组。
尽管这个办法能够多个组件联结调试,然而性能也是无限的,不如间接代码编辑的快。
5、运行 storybook
npm i -D node-sass@5.0 sass-loader@10.0.5 style-loader@1.3.0 // 装置相干插件
npm run storybook
运行后的样子是这样的,从此你就能够开始扩大组件库了。