Storybook 是以后最风行的 UI 组件开发环境,次要性能就是提供组件独立运行环境,不便编写组件应用样例,每个样例称之为一个“story”。有了它,就能够不便的在我的项目中提取通用组件,治理本人的组件库。
并且,它还能够通过丰盛的插件实现可交互测试,响应式布局,文档生成、设计稿预览等性能,让开发工作更加专一,和设计人员的合作更轻松。
装置 Storybook
Storybook 有很丰盛的自定义配置项和大量的插件,能够适配各种开发场景,不过这也让我的项目的搭建变得很简单,很新人劝退。????
好在最近更新的 6.0 版本之后,我的项目能够实现零配置搭建,就像 Spring Boot 对 Spring 的简化,让我的项目创立变得分外简略,当初一行命令就能够实现我的项目搭建。
Storybook 反对各种支流组件框架,这里以 Angular 来论述。
创立 Angular 我的项目
首先默认全局曾经装置了 Angular CLI:npm install -g @angular/cli
。顺便一提,Angular 11 大幅晋升了构建速度和打包体积,没有破坏性改变,强烈安利。????
在指定目录(如 D:\projects)下运行 ng new storybook-example
创立一个 Angular 我的项目,依据提醒交互性的配置我的项目生成即可。
初始化 Storybook
接着在这个我的项目门路下(D:\projects\storybook-example)运行命令 npx sb init
即可实现 Storybook 的搭建。它会依据我的项目的依赖主动配置 Storybook。只须要这么一行命令,Storybook 就能够主动装置到我的项目中去。
装置结束后,运行 npm run storybook
即可看到 storybook 胜利运行了,so easy!????
初始化做了什么?
尽管我的项目运行起来了,不过忽然主动创立了一堆未知的文件,也让人心里没底,来看看我的项目初始化做了哪些事件吧。
-
???? 装置所需的依赖包:因为辨认到当前目录下是一个 Angular 我的项目,所以装置的是 Angular 版本的 Storybook 依赖包。
- “@compodoc/compodoc”: Angular 的组件文档生成工具。
- “@storybook/addon-actions”: 用以记录事件触发的插件。
- “@storybook/addon-essentials”: 官网保护的插件汇合,带有默认配置。
- “@storybook/addon-links”: 用以给组件 story 创立链接。
- “@storybook/angular”: storybook 针对 Angular 的依赖。
-
???? 设置 npm 脚本:
- “storybook”: 本地运行 Storybook
- “build-storybook”: 编译打包 Storybook 我的项目
-
???? 在我的项目根目录创立 .storybook 文件夹,增加默认配置:
- main.js:我的项目的全局配置文件,定义了 story 的查找门路,以及引入的插件。
- preview.js:我的项目的渲染配置,包含全局款式的引入,通用性的变量等。
- tsconfig.json:自动识别我的项目采纳 typescript 后主动生成的配置文件
- ???? 在 src/stories 目录下创立三个组件(button、header、page),以及它们的 story 示例
编写 stories
story 用于展现组件某个状态,每个组件能够蕴含任意多个 story,用来测试组件的各种场景。依据默认配置,只须要在组件的文件夹中,以 **.component.stories.ts 的格局创立即可。
story 语法
根本编写语法很简略,是 export
任意多个 function,每一个就是一个 story。导出次要分两种:
-
default export:默认导出,提供组件级别的配置信息,例如以下配置会注明组件的归类,并提供 Button 组件的信息,以便渲染这个组件。
// Button.stories.ts import Button from './button.component'; export default { title: 'Components/Button', component: Button, }
-
named export:命名导出,用以形容 story,如上所说,一个组件能够有若干个 story。
// Button.stories.ts // 创立一个模板,不便在后续的 story 中复用 const Template = (args: Button) => ({props: args,}); export const Primary = Template.bind({}); // 复制 Template Primary.args = {background: '#ff0', label: 'Button'}; Primary.storyName = "次要状态" // 自定义 story 名 export const Secondary = Template.bind({}); Secondary.args = {...Primary.args, label: '????????????????'}; // 复用上一个 story 的配置 export const Tertiary = Template.bind({}); Tertiary.args = {...Primary.args, label: '????????????????'} // 再来一个
通过复制模板 function,能够创立若干个 story,传入不同的参数,就能够别离渲染出组件的不同状态。每个 story 的名字默认是 function 名,也能够自定义。
Args(属性)
上一节看到了怎么去写一个 Story 文件,不过外面重复用到的 args 是什么呢?
它代表组件的输出属性(Angular 中的 @input(),Vue/React 中的 props),它有 2 个层级,不便灵便配置。
-
story 层级:
// Button.stories.ts const Template = (args: Button) => ({props: args,}); // 在这个 story 中传入组件属性,只影响以后 story export const Primary = Template.bind({}); Primary.args = { primary: true, label: 'Primary', };
-
组件层级:
// Button.stories.ts import Button from './button.component'; // 组件层级(默认导出)中传入组件属性,// 这个 Button 组件的所有 stories 的 primary 属性都会是 true export default { title: "Button", component: Button, args: {primary: true,}, }
就像上一节所看到的,不同的 story 的 args 是能够复用的,这里用到了 ES6 的解构语法:
const Primary = ButtonStory.bind({});
Primary.args = {
primary: true,
label: 'Button',
}
// 复用 Primary story 的 args,并笼罩 primary 属性
const Secondary = ButtonStory.bind({});
Secondary.args = {
...Primary.args, // 合并上一个 args 对象
primary: false,
}
简略的导出几个 function,这个按钮组件的测试用例就写好了,看看成果
能够看到,这个按钮组件能够独立于我的项目运行了,并且左边工具栏能够自在更改它的属性,实时查看属性扭转后的成果,还能够主动生成组件文档。
有 story 做示例,有实时的控制台,有文档,再也不怕写好的组件他人不晓得怎么用了。????
额定的配置项
除了写给组件写 story,很多时候也会须要配置插件,或者给组件提供额定的性能,这里看看是如何配置的吧。
Parameters(参数)
Parameters 用以配置 Storybook 和 插件,具备全局、组件、story 三个层级。
Story 领有大量的插件,以下以简略的 backgrounds 插件举例,它用来管制组件容器的背景色,默认自带黑 / 白两色。
-
全局定义在根目录 .storybook/preview.js 下,会影响所有的 stories。这样配置后,每个 story 界面下都能够抉择红 / 绿两色背景:
// .storybook/preview.js export const parameters = { backgrounds: { values: [{ name: 'red', value: '#f00'}, {name: 'green', value: '#0f0'}, ], }, };
-
组件层级下定义,会让这个组件的所有 stories 都能够抉择指定的背景色
// Button.story.ts export default { title: 'Button', component: Button, parameters: { backgrounds: { values: [{ name: 'red', value: '#f00'}, {name: 'green', value: '#0f0'}, ], }, }, };
-
story 层级下的定义只会影响以后 story,其余 story 就只能抉择默认的黑 / 白两色了。
// Button.story.ts export const Primary = Template.bind({}); Primary.args = { primary: true, label: 'Button', }; // 红绿背景只在这个 story 下能够抉择 Primary.parameters = { backgrounds: { values: [{ name: 'red', value: '#f00'}, {name: 'green', value: '#0f0'}, ], }, };
Parameters 的配置是能够继承,同名的子级会笼罩父级的定义。
Decorators(装璜器)
每个 Decorator 也是 function,用来包裹 story,放弃原有的 story 不变的状况下,额定给它增加额定的 DOM 元素、引入上下文环境、增加假数据等等。
和 Parameters 一样,它也能够定义在全局 / 组件 /story 三个层级,每个 Decorator 按定义程序顺次执行,从全局到 story。
例如,用一个额定的 <div>
包裹每个 story 的组件渲染:
// button.stories.ts
import {Meta, Story} from '@storybook/angular';
import {ListComponent} from './list.component';
export default {
title: 'Example/List',
component: ListComponent,
decorators: [(storyFunc) => {const story = storyFunc();
return {
...story,
template: `<div style="height: 60px">${story.template}</div>`,
};
}
]
} as Meta;
这样一来,这个列表组件的所有 story,都会展现出它在一个 60 像素高的容器内的出现成果。
除了给组件包裹额定的元素,再例如为复合组件增加组件依赖:
// List.stories.ts
import {moduleMetadata} from '@storybook/angular';
import {CommonModule} from '@angular/common';
import List from './list.component';
import ListItem from './list-item.component'
// 给 list 组件增加它须要的组件和模块依赖
export default {
title: 'List',
component: List,
decorators: [
moduleMetadata({declarations: [ListItem],
imports: [CommonModule],
}),
],
};
const Template = (args: List) => ({
component: List,
props: args,
});
就像平时须要在 ngModule 中申明似的,moduleMetadata
装璜器能够轻松测试各种组件,让你能在 Storybook 中从小到大搭建组件库。
组件驱动开发
古代用户界面更加简单,在突飞猛进的技术倒退下,人们更加冀望独特,共性的用户体验。但这也意味着前端和设计须要给 UI 界面嵌入更多的逻辑和设计,这让前端变得原来越重,界面也越加简单难以保护和测试。
将 UI 模块化拆散也成了趋势,拆散页面逻辑到一个个独立的交互模块中,将简单的业务拆分解构,每个模块易于测试,组合和复用。所以当初组件化框架成了相对的支流。类似的,以后微服务和容器化也变得十分风行。
开发流程
那么组件驱动的开发又是如何呢?
- 一次编写一个组件 :首先编写一个个独立组件,定义它们的输出属性和输入事件,始于微末(例如 Avatar、Button、Input、Tooltip)。没错,这就是咱们相熟的一个个组件库所做的事件:Material、Antd、ElementUI……
- 组合组件 :形成更简单的业务模块,形成新的性能(例如 Forms、Header、List、Table)。
- 拆卸页面 :将业务模块构建出页面,应用假数据来模仿页面的各种应用场景和边缘用例。(例如首页、设置页、个人主页)
- 集成页面到利用 :将页面与后盾数据接口,业务逻辑服务层对接,形成理论应用程序(例如 xx 监管零碎、xxx 商城、xx 官网)
所以 Storybook 初始化我的项目后,创立了 button、header、page 三个组件示例,它们就代表了这样的开发阶梯流程。
实用场景
没有万精油的开发模式,总是须要按需抉择技术栈和开发模式的,咱们重要去理解每个优劣场景,这个也不例外。
劣势;
- 高质量: 通过编写各种 stories 来验证组件的运行场景,测试用例越多,组件品质越发牢靠和强壮。
- 易测试: 在组件级别进行测试,将 debug 细化,比按业务页面测试更省力准确。
- 开发和设计并行:讲 UI 按组件模块化开发,能够让设计和前端开发更严密的单干,不同我的项目共享资源。
劣势:
- 工夫周期: 相比针对页面一把梭似的开发,针对组件谨严设计 api,编写 story,思考复用性和边缘场景。我的项目的开发工夫周期必然会进步,这对外包的小伙伴来说,可就不敌对了。
- 页面类利用:整个利用在开发和设计角度来看,都是几个残缺页面的汇合,页面间没有太多能够复用的元素,整夜开发和划分组件差异不大(开发各种可视化大屏可能会有同感)
所以,组件驱动开发,更适宜复用场景丰盛的系列利用场景,我的项目生命周期短缺,品质要求高,前端和设计单干严密的团队(或者,咱们本人一个人包圆儿的集体我的项目????)
总结
本篇简略介绍了 Storybook 这一组件开发工具,次要蕴含几点:
- 在已有的 Angular 我的项目下,通过一行命令初始化了 Storybook 开发环境,它主动装置了依赖,创立了默认配置,并在我的项目里生成了三个示例。运行它设置好的命令行,即可看到组件测试界面。
-
介绍了如何编写组件的 story。
- 编写按键组件的三个 story 用例,实现用例的复用。
- 用 parameter 配置背景插件。
- 用 decorator 给组件增加额定的外层 DOM、传递组件的模块依赖。
- 介绍组件驱动开发模式,剖析其优劣场景。
纸上得来终觉浅,还是得把它融入咱们理论的开发场景,看看它是如何驱动我的项目的开发的。所以,一起来体验可视化的测试驱动开发,实现一个残缺的业务页面吧,咱们下一篇见!????