原文连接javascript
对于一名前端开发者,必须面对的就是组件化开发。我作Angular开发已经有些日子了,也曾为本身的项目开发过通用组件,但仅是在项目内部使用,并且是直接用业务界面对组件进行测试。若是其余项目要使用这些组件,也是使用老土的拷贝方式来进行复用。偶然发现StoryBook,研究了下,顿生好感,原来组件开发能够这么简单的管理和测试,还能够编写清晰明了的说明文档,对提高组件开发的效率那是大大滴提高。css
本文将以一个基于Material的三级选择组件为例,进行StoryBook实战,实实在在滴体验下StoryBook的强大。html
StoryBook给开发这提供了一个强大的组件开发的生态环境,涉及组件的测试、实景展现、文档,以及术语。常见术语解释以下:前端
以下是经常使用的Addon:java
对于StoryBook入门内容,在网上能够找到不少,同时StoryBook for Angular中也有入门级的详细解释,这里不赘述。 下面来个实战演练。node
三级级联选择组件,在项目中比较经常使用,好比省市区、多级分类等,通用的UI大多仅提供一级选择组件。三级选择则须要根据业务需求,开发者本身编写。因而我本身写了一个省市区的三级选择的组件。 首先为这个组件建立了独立的Angular工程:git
ng new cityselect
cd cityselect
复制代码
组件目录以下: github
组件名称为MatCascaderComponent,指望的运行效果以下: shell
在cityselect中安装StoryBook,命令以下:npm
npx -p @storybook/cli sb init --type angular
//同时安装以下Addon
npm install --save @storybook/addon-options
复制代码
执行 npm run storybook 成功后,访问 http://localhost:6006 能够看到StoryBook的界面以及缺省的Story。
StoryBook提供了两种Story的写法,第一种是直接使用组件,第二种是使用Html标签。
因为组件使用到了Materail的相关Module,Story中须要先将这些外部Module引入,这里用到了:moduleMetadata。
能够单独对每一个Story设置moduleMetadata:
.add( "直接使用组件", () => ({
component: MatCascaderComponent, //直接使用组件
props: {},
//仅对当前Story生效
moduleMetadata:{
imports: [BrowserAnimationsModule, MatFormFieldModule, MatSelectModule],
schemas: [],
declarations: [],
providers: [CityCascsdeService, CommonService]
}
}),
{ notes: `缺省是三级地区选择` }
)
复制代码
亦可以使用addDecorator对storiesOf下的全部Story设置moduleMetadata:
.addDecorator(
//对此storiesOf下的全部Story生效
moduleMetadata({
imports: [BrowserAnimationsModule, MatFormFieldModule, MatSelectModule],
schemas: [],
declarations: [],
providers: [CityCascsdeService, CommonService]
})
)
.add( "直接使用组件", () => ({
component: MatCascaderComponent, //直接使用组件
props: {}
}),
{ notes: `缺省是三级地区选择` }
);
复制代码
下面咱们使用Html标签,这个咱们项目中的用法是同样的,因此须要对组件MatCascaderComponent进行声明,一样是在moduleMetadata中:
.addDecorator(
moduleMetadata({
imports: [BrowserAnimationsModule, MatFormFieldModule, MatSelectModule],
schemas: [],
declarations: [MatCascaderComponent], //这里声明下
providers: [CityCascsdeService, CommonService]
})
)
.add("使用HTML标签",() => ({
template: `<ngx-mat-cascader ></ngx-mat-cascader>`,
props: {}
}),
{ notes: `缺省是三级地区选择` }
);
复制代码
此时看到的StoryBook的效果以下:
上面咱们看到组件的样式不对。StoryBook不会自动引入组件须要的CSS文件,须要告诉StoryBook访问哪一个静态文件,详情可参见参考文档。
这里给出主要改动:
.storybook 目录下建立名为 preview-head.html 文件,该文件是为HTML添加自定义的Head内容。内容以下:
<link rel="stylesheet" href="./styles.css" />
复制代码
在src/styles.css文件中引入Materail的CSS:
@import "../node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
@import "../node_modules/bootstrap-material-design/dist/css/bootstrap-material-design.css"
复制代码
package.json文件中修改启动StoryBook的命令,经过 -s 参数指定静态目录
//指定./ 和 ./src均为静态目录
"scripts": {
"storybook": "start-storybook -p 6006 -s ./,./src",
}
复制代码
.storybook目下的修改,必须重启StoryBook。这时咱们看到样式正确了。
上面的Story很是简单,没有参数和Action。下面看看若是设置参数和Action。MatCascaderComponent缺省是个省市区的三级选择组件,可是若是提供不一样的参数,它就会华丽的变身了:
.add( "设置选择数据",() => ({
component: MatCascaderComponent,
props: {
data: [
{
code: "11",
name: "易耗品",
children: [
{
code: "1101",
name: "打印机",
children: [
{ code: "110101", name: "彩色墨盒" },
{ code: "110102", name: "黑色墨盒" }
]
}
]
},
{
code: "12",
name: "食品",
children: [
{
code: "1201",
name: "快餐",
children: [
{ code: "120101", name: "薯条" },
{ code: "120102", name: "热狗" }
]
}
]
}
],
level1placeholder: "选择分类",
level2placeholder: "选择货区",
level3placeholder: "选择货架",
allTitle: "所有",
showAll: true,
onZoneChange:action('onZoneChange')
}
}),
{ notes: '这是一个三级商品选择组件' }
);
复制代码
效果以下:
Html标签测试设置参数参见以下示例代码:
.add( "设置初始值", () => ({
template: `<ngx-mat-cascader [data]="basedatas" [separate]="separate" [(value)]="selectvalue" (onZoneChange)="zoneChange()" ></ngx-mat-cascader>`,
props: {
basedatas:[...],
separate:'-',
selectvalue:'11-1101',
zoneChange:action('change')
}
}),
{ notes: '这是一个三级商品选择组件' }
);
复制代码
是否是方便的不能再方便?对拷贝、粘贴深恶痛绝的我,看到了组件开发的春天。
在上面的示例中,你会发现notes属性,就是备注的意思。一个完美的备注即提高了Story的可读性,也方便后期对组件的维护,更能够经过备注向使用者展现展现本身的组件。 StoryBook提供了两种途径,一是在Story的notes属性中直接使用MarkDown,二是使用一个MarkDown文件。 以下是在notes属性中直接使用MarkDown,须要注意的是折行后前面不能有空格:
.add("设置选择数据", () => ({
component: MatCascaderComponent,
props: {...}
}),
{ notes: ` # 我是一级标题 ## 我是二级标题,行首不能有空格,下同 ### 我是三级标题 1. 我是列表1 2. 我是列表2 ` }
)
复制代码
效果以下:
若是备注一两句能说描述清楚Story,上述方法可行。但对于复杂的Story,仍是一个MarkDown文件更方便。要使用md文件作备注,须要作些改动,要让代码识别出MarkDown文件:
//引入对md文件的支持,在.storybook目录下建立typings.d.ts文件,内容以下:
declare module "*.md" {
const content: string;
export default content;
}
// 在.storybook/tsconfig.json文件添加:
"files": [
"./typings.d.ts"
]
// story中引入文件:
import * as readme from '../app/components/select/README.md';
.add("选择测试",() => ({
component: MatCascaderComponent,
props: {...}
}),
{ notes: readme }
);
复制代码
效果以下:
StoryBook还能够打包成静态页面放在公网上,供你们品评。可是界面左上角显示的仍是StoryBook,须要换下,这就涉及的修改StoryBook的主题了,这里仅提供名字和连接更改的方法:
import { addParameters } from '@storybook/angular';
import logo from '../src/assets/img/dteam.svg';
addParameters({
options: {
theme:{
brandTitle:'DTeam组件库',
brandUrl: 'https://github.com/dteam-top'
},
}
});
复制代码
效果以下:
关于主题的更详细的说明,请参见文档2。
经过对StoryBook的学习和实践,我以为它的确不错,对于组件的开发、测试、文档化很是方便:
这些对于前端开发的工做,提供了很多改进:
可是“人无完人”,我在使用StoryBook过程当中,也发现了一些问题:
任何工具都是入门易、深耕难,StoryBook亦是如此,这须要开发人员提高组件化思惟,并结合更多的实践,才能让它更好的助力前端开发。