原文連接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亦是如此,這須要開發人員提高組件化思惟,並結合更多的實踐,才能讓它更好的助力前端開發。