What
Storybook官网
隔离UI组件,支持独立调试&测试,统一展示项目组件库。
Why
项目中抽离的组件较多,但并没有集中展示出来具体有些什么,而是分布在各个使用的业务场景中。对于新接触项目的开发人员来说,由于不清楚业务场景,考虑复用组件时不是很直观。
How
最新搭建方案(2020.12.30)
1.三行命令迅速启动示例页
npx -p @storybook/cli sb init
# 启动
npm run storybook
# 启动时报错提示找不到这个包 安装下下再启动
npm install @vue/babel-preset-app --save-dev
成功启动:
跟旧版本相比,自动生成的文件中demo更完善,上手更方便啦
2.package.json
中添加脚本
{
"scripts": {
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook -o ./docs"
}
}
./docs
是输出的静态文件夹,不指定的话默认是storybook-static
。
旧版本搭建方案(@storybook/vue v5.3.x)
参考官方指南,选择Manual setup
1.添加依赖
$ cnpm install @storybook/vue -S
$ cnpm install vue-loader vue-template-compiler @babel/core babel-loader babel-preset-vue -S
2.package.json
中添加脚本
{
"scripts": {
"storybook": "start-storybook"
}
}
3.添加less-loader
,注入全局less变量
// .storybook/main.js
const path = require('path')
module.exports = {
webpackFinal: async (config, { configType }) => {
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
// You can change the configuration based on that.
// 'PRODUCTION' is used when building the static version of storybook.
// Make whatever fine-grained changes you need
config.module.rules.push({
test: /\.less/,
use: [
'style-loader',
'css-loader',
'less-loader',
{
loader: 'style-resources-loader',
options: {
patterns: [
path.resolve(__dirname, '../src/assets/styles/variable.less')
]
}
}
],
include: path.resolve(__dirname, '../')
})
return config
}
}
4.添加路径别名
// .storybook/main.js
config.resolve.alias = {
...config.resolve.alias,
'@': path.resolve(__dirname, '../src'),
'@com': path.resolve(__dirname, '../src/components')
}
5.启动
$ npm run storybook
最小版本组件
项目结构
// .storybook/config.js
import { configure } from '@storybook/vue'
configure(require.context('./stories', true, /\.stories\.js$/), module)
// .storybook/stories/global.stories.js
import Vue from 'vue'
import Toggle from './../../src/components/toggle/index.vue'
Vue.component('Toggle', Toggle)
export const toggle = () => `
<toggle :data="[
{ label: 'toggle1', value: '1' },
{ label: 'toggle2', value: '2' }
]"
/>
`
export default { title: 'Global' }
最小版本over~
接下来把组件们都写进stories就大功告成啦~
一个小插曲
几天之后,npm run storybook
启不起来一直报错缺依赖,直接rimraf node_modules/
重新npm i
完事儿~
Addons
Knobs
动态交互展示组件属性
安装
cnpm install @storybook/addon-knobs -S
在.storybook/main.js
中引入插件
module.exports = {
addons: ['@storybook/addon-knobs/register']
}
使用
// .storybook/stories/panel.stories.js
import { storiesOf } from '@storybook/vue'
import { withKnobs, boolean, text } from '@storybook/addon-knobs'
import JhlDialogDetail from '@com/jhl-dialog-detail/index.vue'
export default {
title: 'Panel',
decorators: [withKnobs]
}
export const egJhlDialogDetail = () => ({
components: { JhlDialogDetail },
props: {
visible: { default: boolean('visible', true) },
title: { default: text('Text', '标题') },
dlgWidth: { default: text('dlgWidth', '66%') }
},
data () {
return {
data: [
{
label: '基本信息',
children: [
{ label: '中文名', prop: 'labelNameCn', span: 8 },
{ label: '英文名', prop: 'labelNameEn', span: 8 },
{ label: '实体', prop: 'entityName', span: 8 },
{ label: '一级主题', prop: 'firstThemeName', span: 8 },
{ label: '二级主题', prop: 'secondThemeName', span: 8 },
{ label: '三级主题', prop: 'thirdThemeName', span: 8 }
]
},
{
label: '加工信息',
children: [
{ label: '更新时间', prop: 'labelModifiedTime', span: 8 },
{ label: '业务负责人', prop: 'businessOwnerErp', span: 16, render: 'erp' },
{ label: '口径', prop: 'processDesc', span: 24, render: 'html' }
]
},
{ label: '自定义区域', slot: 'quality' }
],
detail: {
'labelNameCn': 'zm测试',
'labelNameEn': 'zmTest',
'entityName': '用户',
'firstThemeName': '人口属性',
'secondThemeName': '自然属性',
'thirdThemeName': '年龄',
'labelModifiedTime': '2020-05-14 00:00:00',
'businessOwnerErp': 'zhaozimu',
'processDesc': '<p>213来源于X表,来源表关联字段X,标签筛选规则是XX,时间窗口为近X天,标签加工逻辑为XX,标签覆盖量为X,标签更新周期为XX</p>'
}
}
},
template:
`<jhl-dialog-detail
:visible.sync="visible"
:title="title"
:dlg-width="dlgWidth"
:data="data"
:detail="detail"
>
<div slot="quality">'slot' is here~</div>
</jhl-dialog-detail>`
})
效果
Actions
由于组件里都是$emit
抛的事件,Actions
暂时还不支持,待后续研究补充~
storybook-readme
展示markdown文档
安装
cnpm i storybook-readme -D
注册组件
// .storybook/addons.js
import 'storybook-readme/register'
使用
配置
// .storybook/config.js
import { configure, addDecorator, addParameters } from '@storybook/vue'
// UI framework
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
// knobs
import { withKnobs } from '@storybook/addon-knobs'
// readme
import { addReadme } from 'storybook-readme/vue'
import { themes, create } from '@storybook/theming'
const basicTheme = create({
base: 'light',
brandTitle: 'README addon',
brandUrl: 'https://github.com/tuchk4/storybook-readme',
brandImage: null
})
addParameters({
options: {
showPanel: true,
panelPosition: 'right',
theme: basicTheme
// theme: themes.dark,
},
readme: { codeTheme: 'github' }
})
addDecorator(withKnobs)
addDecorator(addReadme)
Vue.use(ElementUI)
configure(require.context('./stories', true, /\.stories\.js$/), module)
使用
//.storybook/stories/toggle.stories.js
import { boolean, number } from '@storybook/addon-knobs'
import Toggle from '@com/toggle/index.vue'
import ToggleReadme from '@com/toggle/index.md'
export default {
title: 'Component',
parameters: {
readme: { sidebar: ToggleReadme }
}
}
export const egToggle = () => ({
components: { Toggle },
props: {
isResetIdx: boolean('isResetIdx', false),
currentIndex: number('currentIndex', 1)
},
data () {
return {
data: [
{ label: 'toggle1', value: '1' },
{ label: 'toggle2', value: '2' },
{ label: 'toggle3', value: '3', status: 'false' }
]
}
},
template:
`<toggle
:data="data"
:is-reset-idx="isResetIdx"
:current-index="currentIndex"
/>`
})
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。