想搞个组件可视化好久了,一开始就是想作个和antd相似的,而后就遇到了一系列的问题javascript
组件可视化的目的:css
调研发现,antd使用的是阿里系的bisheng这个包vue
目的是将markdown转成静态站点,antd就是这样产生的java
这就是本次要说的storybook了,目前3.7w个star,且生态比较好,插件也很多react
npm init -y
npm install @storybook/react --save-dev
npm install react react-dom --save
npm install babel-loader @babel/core --save-dev
复制代码
在package.json中添加webpack
{
"scripts": {
"storybook": "start-storybook"
}
}
复制代码
建立.storybook/config.js文件git
import { configure } from '@storybook/react';
function loadStories() {
require('../stories/index.js');
// 能够添加多个store
// You can require as many stories as you need.
}
configure(loadStories, module);
复制代码
建立../stories/index.js文件github
import React from 'react';
import { storiesOf } from '@storybook/react';
import { Button } from '@storybook/react/demo';
storiesOf('Button', module)
.add('with text', () => (
<Button>Hello Button</Button>
))
.add('with emoji', () => (
<Button><span role="img" aria-label="so cool">😀 😎 👍 💯</span></Button>
));
复制代码
npm run storybook
复制代码
官方提供了三种,我选择了我的认为比较清晰的方式
web
按照上面的设计估计应该就可以知足咱们的需求了chrome
只是简单配置可不行,若是不在一开始就搞好的话,随着后面业务的扩展会带来不少问题,像按需加载这种功能仍是一开始就设计比如较好
修改.storybook/config.js
import { configure } from '@storybook/react';
const req = require.context('../src/components', true, /\.stories\.js$/);
function loadStories() {
req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);
复制代码
addons
**
重要的事情说三遍:
在.storybook配置文件中,添加一个addons.js文件
**在.storybook配置文件中,添加一个addons.js文件
**在.storybook配置文件中,添加一个addons.js文件
addons.js文件是用来维护插件的配置文件
官网上Addons目录就是官方推荐的插件列表,开始一个个尝试
npm i @storybook/addon-knobs -D
复制代码
找到.storybook/addons.js在其中添加一句话
import '@storybook/addon-knobs/register';
复制代码
按照github地址,添加示例代码
import React from 'react';
import { storiesOf } from '@storybook/react';
import { withKnobs, text, boolean, number } from '@storybook/addon-knobs';
const stories = storiesOf('Storybook Knobs', module);
// Add the `withKnobs` decorator to add knobs support to your stories.
// You can also configure `withKnobs` as a global decorator.
stories.addDecorator(withKnobs);
// Knobs for React props
stories.add('button', () => (
<button disabled={boolean('不可用', false)} > {text('文案', '牛逼的knobs')} </button>
));
// Knobs as dynamic variables.
stories.add('as dynamic variables', () => {
const name = text('Name', 'Arunoda Susiripala');
const age = number('Age', 89);
const content = `I am ${name} and I'm ${age} years old.`;
return (<div>{content}</div>);
});
复制代码
上面一共作了几件事情:
直接看效果
上面例子中,第二个case,包含计算变量
// Knobs as dynamic variables.
stories.add('as dynamic variables', () => {
const name = text('Name', 'Arunoda Susiripala');
const age = number('Age', 89);
const content = `I am ${name} and I'm ${age} years old.`;
return (<div>{content}</div>);
});
复制代码
npm i -D @storybook/addon-actions
复制代码
import '@storybook/addon-actions/register';
复制代码
import { storiesOf } from '@storybook/react';
import { action, configureActions } from '@storybook/addon-actions';
import Button from './button';
storiesOf('Button', module).add('default view', () => (
<Button onClick={action('button-click')}>Hello World!</Button>
));
复制代码
import { storiesOf } from '@storybook/react';
import { actions } from '@storybook/addon-actions';
import Button from './button';
// This will lead to { onClick: action('onClick'), ... }
const eventsFromNames = actions('onClick', 'onMouseOver');
// This will lead to { onClick: action('clicked'), ... }
const eventsFromObject = actions({ onClick: 'clicked', onMouseOver: 'hovered' });
storiesOf('Button', module)
.add('default view', () => <Button {...eventsFromNames}>Hello World!</Button>)
.add('default view, different actions', () => (
<Button {...eventsFromObject}>Hello World!</Button>
));
复制代码
npm i @storybook/addon-storysource --dev
复制代码
module.exports = function({ config }) {
config.module.rules.push({
test: /\.stories\.jsx?$/,
loaders: [require.resolve('@storybook/addon-storysource/loader')],
enforce: 'pre',
});
return config;
};
复制代码
这个和前面两个插件不一样之处就在这,它须要在webpack中添加一个loader,经过storybook自己的webpack对外暴露,对其添加插件
npm i -D @storybook/addon-info
复制代码
addon-info采用的是修饰器模式,能够全局添加,也能够局部添加
addDecorator(withInfo); // Globally in your .storybook/config.js.
复制代码
storiesOf('Component', module)
.addDecorator(withInfo) // At your stories directly.
.add(...);
复制代码
import React from 'react';
import PropTypes from 'prop-types';
const Test = (props)=><div>{props.children}</div>
Test.propTypes = {
text: PropTypes.string.isRequired,
onDelete: PropTypes.func,
}
export default Test
复制代码
添加addons-info插件后,就会增长showinfo按钮
import React from 'react';
import PropTypes from 'prop-types';
const Test = (props)=><div>{props.children}</div>
Test.defaultProps = {
text: '默认值',
onDelete: () => {}
};
Test.propTypes = {
/** 这里text是注释 */
text: PropTypes.string.isRequired,
/** 这里onDelete是注释 */
onDelete: PropTypes.func,
}
export default Test
复制代码
viewport你们都很熟悉,这个就是用来搞移动端的
npm i --save-dev @storybook/addon-viewport
复制代码
在.storyboos/config中注册
import '@storybook/addon-viewport/register';
复制代码
import React from 'react';
import { configure,addDecorator,addParameters } from '@storybook/react';
// config.js
import { withInfo } from '@storybook/addon-info';
addDecorator(withInfo);
addParameters({
viewport: { defaultViewport: 'iphone6' },
});
const req = require.context('../src/components', true, /\.stories\.js$/);
function loadStories() {
req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);
复制代码
这里就是使用addParameters方法,很方便就能够
这部分是测试用例相关,短期内啃不下来,待后面有时间再补充
npm i @storybook/addon-a11y --dev
复制代码
修改addons
import '@storybook/addon-a11y/register';
复制代码
在config文件中添加
addDecorator(withA11y);
addParameters({
a11y: {
// ... axe options
element: '#root', // optional selector which element to inspect
config: {}, // axe-core configurationOptions (https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#parameters-1)
options: {} // axe-core optionsParameter (https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter)
},
});
复制代码
ok,这样的话,若是书写不符合规范的按钮,则会报错
这个插件解决的问题是,story之间的相互跳转,用法也很简单,只须要参考文档就好
目前比较好的插件列表以下