想搞个组件可视化很久了,一开始就是想做个和antd类似的,然后就遇到了一系列的问题
组件可视化的目的:
- 历史组件可感知,能够做到信息同步
- 能够改变开发流程,能够提前进行组件的视觉验收
- 便于后期的视觉规范统一
Q1:如何搞个和antd类似的组件库?
调研发现,antd使用的是阿里系的bisheng这个包
Q2:bisheng的解决的问题是?
目的是将markdown转成静态站点,antd就是这样产生的
Q3:bisheng存在的问题?
- 很久无人维护,文档更新等都比较滞后
- 且文档比较难读,上手比较麻烦
Q4:除了bisheng市面上还有什么解决方案?
这就是本次要说的storybook了,目前3.7w个star,且生态比较好,插件也不少
Q5:storybook怎么上手?
step1:安装依赖
npm init -y
npm install @storybook/react --save-dev
npm install react react-dom --save
npm install babel-loader @babel/core --save-dev
复制代码
step2:添加script脚本
在package.json中添加
{
"scripts": {
"storybook": "start-storybook"
}
}
复制代码
step3:添加config文件
创建.storybook/config.js文件
import { configure } from '@storybook/react';
function loadStories() {
require('../stories/index.js');
// 可以添加多个store
// You can require as many stories as you need.
}
configure(loadStories, module);
复制代码
step4:开始写story
创建../stories/index.js文件
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>
));
复制代码
step5:跑起来
npm run storybook
复制代码
效果
总结:storybook按照配置,跑起来还是比较轻松的
Q6:如何设计目录结构?
官方提供了三种,我选择了个人认为比较清晰的方式
- button.js是组件代码
- button.stories.js是故事代码
按照上面的设计估计应该就能够满足我们的需求了
Q7:如何按需加载?
只是简单配置可不行,如果不在一开始就搞好的话,随着后面业务的扩展会带来很多问题,像按需加载这种功能还是一开始就设计好比较好
修改.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);
复制代码
Q8:storybook插件是什么?
- 前面有了组件库展示,但距离可查看api、可测试、可调整样式等差距还很大
- 这些额外的功能就需要添加依赖来解决了
- 在storybook中插件概念叫做
addons
Q9:啥是addons?
- addons是添加的意思
- 在storybook则用来将其用作表示增加的功能
**
重要的事情说三遍:
在.storybook配置文件中,添加一个addons.js文件
**在.storybook配置文件中,添加一个addons.js文件
**在.storybook配置文件中,添加一个addons.js文件
addons.js文件是用来维护插件的配置文件
Q10:如何体验第一个addons?
官网上Addons目录就是官方推荐的插件列表,开始一个个尝试
Q11:什么是addons-knobs?
这个可就牛逼了,knobs主要是用来提供动态调整交互的能力,实践一下
step1:安装依赖
npm i @storybook/addon-knobs -D
复制代码
step2:添加配置项
找到.storybook/addons.js在其中添加一句话
import '@storybook/addon-knobs/register';
复制代码
step3:修改已有的stories
按照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>);
});
复制代码
上面一共做了几件事情:
- 在stories上添加了一个修饰器
- 在button上添加了对属性的包装,例如text()、boolean()等相当于对属性进行了绑定
直接看效果
step4:双向绑定效果
可以看到,我们订阅的两个数据类型已经显示在了Knobs中了,此时修改内容,组件内容也随之改变
step5:计算属性
上面例子中,第二个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>);
});
复制代码
当修改age后,也会重新渲染
Knobs极其强大:
- 这个计算属性,很像vue中的computed属性,当数据改变即可以改变交互
- 同时也可以快速验证多种状态
- 也可以快速验证边界情况
Q12:什么是addons-actions
Actions用来获取用户点击信息,这个具体使用暂时没太想到场景,看了demo,目前是用来区分具体点击的位置
step1:安装依赖
npm i -D @storybook/addon-actions
复制代码
step2:修改.storybook/addons.js
import '@storybook/addon-actions/register';
复制代码
step3:绑定单个事件
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>
));
复制代码
step4:绑定多个事件
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>
));
复制代码
Q13:什么是addons-storysouce
这个理解起来还是相对简单的,目的就是在控制台中显示故事源
step1:安装依赖
npm i @storybook/addon-storysource --dev
复制代码
step2:创建webpack.config.js
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对外暴露,对其添加插件
step3: 查看源码效果
Q14:什么是addon-info?
这个info插件也十分强大,能够快速将组件中的配置信息,转换成markdown可阅读模式中组件信息
step1:安装依赖
npm i -D @storybook/addon-info
复制代码
step2:添加插件
addon-info采用的是修饰器模式,可以全局添加,也可以局部添加
- 全局修饰就是在config中全局添加
addDecorator(withInfo); // Globally in your .storybook/config.js.
复制代码
- 局部修饰的花,就在stories中添加
storiesOf('Component', module)
.addDecorator(withInfo) // At your stories directly.
.add(...);
复制代码
step3:在组件代码中添加propTypes
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按钮
点击showinfo,就可见
- 自动将组件名称转为了markdown
- 自动将组件代码转为了markdown
- 自动将propsTypes转为了表格
step4:在组件代码中添加默认值、描述
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
复制代码
- 默认值通过defaultProps设置
- 注释通过在属性上添加注释来实现
Q15:什么是addon-viewport?
viewport大家都很熟悉,这个就是用来搞移动端的
step1:安装依赖
npm i --save-dev @storybook/addon-viewport
复制代码
step2:注册插件
在.storyboos/config中注册
import '@storybook/addon-viewport/register';
复制代码
step3:全局添加
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方法,很方便就可以
这样默认就有了一批viewpoint,这一块具体配置,就慢慢读文档就好了
Q16:什么是addons-shots
这部分是测试用例相关,短时间内啃不下来,待后面有时间再补充
Q17:什么是addon-backgrounds
这个主要是用来设置背景色,非必须,可有可无
Q18:什么是addon-a11y
这个相当与lint类的功能,在实际项目中还是很有用的
step1:安装依赖
npm i @storybook/addon-a11y --dev
复制代码
step2:注册插件
修改addons
import '@storybook/addon-a11y/register';
复制代码
step3:添加修饰器和参数
在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,这样的话,如果书写不符合规范的按钮,则会报错
Q19:什么是addon-console
前面很多插件,添加了很多信息到操作台上,所以很多人容易忽略掉chrome控制台内部的信息,所以这个插件很有意义,就是用来把控制台的信息映射到操作台上,具体配置也比较简单,按照文档操作即可
Q20:什么是addon-links
这个插件解决的问题是,story之间的相互跳转,用法也很简单,只需要参考文档就好
Q21:除了这些官方推荐插件外还有哪些?
目前比较好的插件列表如下
- Storyshots: 快照测试。
- Specs: 交互测试。
- Notes: 在 story 中添加备注。
- Info: 用于创建 css 框架手册。
- Readme: 将 markdown 导入为 story。
- actions: 显示事件的 event 对象。
- Intl: 添加 locales 面板,用于切换语言。
- State: 添加 state 面板,展示或更新 state,重绘视图。
- Props Combinations: 配置可能有的props,一次性绘出多个组件作对比。
- Knobs: 页面上变更 props 重绘视图。
- Links: 通过 linkTo 函数或 LinkTo 组件链接多个 story,支持点击跳转。
- Story-router: 装饰器,支持 storybook 使用 react-router 等路由组件。
- Backgrounds: 切换背景图或背景颜色。
- i18n tools: 切换文字对齐方式,左对齐或右对齐。
- Material-UI: 添加并切换自定义主题。
- Host: 装饰器,在页面上以盒模式展示组件。
- Chapters: 在同一个 story 中以章节形式展示多个组件。
- Options: 调整 storybook 页面外观,切换为全屏等。
- Console: 将浏览器控制台 console 信息输出到 storybook log 面板。
- JSX preview: 展示及拷贝 JSX 代码。
- Versions: 添加版本号,查看各版本的变化。
- Apollo: 添加 Apollo client,模拟 GraphQL 查询。
- Screenshot: 保存网页截图。
- Styles: storybook 预览界面添加自定义样式。
- Figma: 添加 Figma 设计面板。
Q22:总结有哪些?
- 最爽的点:如果storybook直接扔进项目里,可以共享一套webpack配置,且组件在业务中和story中能够同时同步,实时同步
- 解决的问题:
- storybook主要解决的是历史组件的展示
- 也可改变验收流程,先进行组件验收,再进行业务验收
- 同时也有利于新同学上手
- 设计划分:
- 第一阶段:先把storybook集成在一起,便于提升效能
- 第二阶段:提取成熟组件,到公共层面,便于其他项目使用
- 第三阶段:组件和story分离,变成两个项目维护,保持组件纯净,story作为文档解决方案
Q23:待办有哪些?
- 在showinfo中展示组件
- 自定义markdown中的表格样式
- 添加测试用例的开发(addons-shots)
- background添加颜色