StoryBook實戰

原文連接javascript

對於一名前端開發者,必須面對的就是組件化開發。我作Angular開發已經有些日子了,也曾爲本身的項目開發過通用組件,但僅是在項目內部使用,並且是直接用業務界面對組件進行測試。若是其餘項目要使用這些組件,也是使用老土的拷貝方式來進行復用。偶然發現StoryBook,研究了下,頓生好感,原來組件開發能夠這麼簡單的管理和測試,還能夠編寫清晰明瞭的說明文檔,對提高組件開發的效率那是大大滴提高。css

本文將以一個基於Material的三級選擇組件爲例,進行StoryBook實戰,實實在在滴體驗下StoryBook的強大。html

術語解釋

StoryBook給開發這提供了一個強大的組件開發的生態環境,涉及組件的測試、實景展現、文檔,以及術語。常見術語解釋以下:前端

  1. Addon:相似Plugin,StoryBook中的功能組件以及擴展以Addon形式存在,開發者亦能夠自行編寫Addon來擴展StoryBook的功能;
  2. Story:相似用例,是組件的各類使用場景;
  3. Decorator:就是給Story作個包裝,能夠是樣式包裝、模塊元數據包裝、類型包裝等。
  4. Notes:備註,能夠爲每一個Story設置Notes,支持MarkDown語法。

以下是經常使用的Addon:java

  • addon-actions:組件操做事件,如click、change
  • addon-links:連接,如某個Story中單擊按鈕,連接到另外一個Story中
  • addon-notes:Story的備註
  • addon-options:調整StoryBook的外觀
  • addon-knobs:在頁面上改變變量

對於StoryBook入門內容,在網上能夠找到不少,同時StoryBook for Angular中也有入門級的詳細解釋,這裏不贅述。 下面來個實戰演練。node

建立本身的組件

三級級聯選擇組件,在項目中比較經常使用,好比省市區、多級分類等,通用的UI大多僅提供一級選擇組件。三級選擇則須要根據業務需求,開發者本身編寫。因而我本身寫了一個省市區的三級選擇的組件。 首先爲這個組件建立了獨立的Angular工程:git

ng new cityselect
cd cityselect
複製代碼

組件目錄以下: github

目錄結構

組件名稱爲MatCascaderComponent,指望的運行效果以下: shell

指望的運行效果

StoryBook實戰

在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

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標籤

下面咱們使用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的效果以下:

CSS未引入

引入外部CSS

上面咱們看到組件的樣式不對。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。這時咱們看到樣式正確了。

正確CSS

設置參數的Story

上面的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: '這是一個三級商品選擇組件' }
);
複製代碼

是否是方便的不能再方便?對拷貝、粘貼深惡痛絕的我,看到了組件開發的春天。

爲Story寫備註

在上面的示例中,你會發現notes屬性,就是備註的意思。一個完美的備註即提高了Story的可讀性,也方便後期對組件的維護,更能夠經過備註向使用者展現展現本身的組件。 StoryBook提供了兩種途徑,一是在Story的notes屬性中直接使用MarkDown,二是使用一個MarkDown文件。 以下是在notes屬性中直接使用MarkDown,須要注意的是折行後前面不能有空格:

.add("設置選擇數據", () => ({
    component: MatCascaderComponent,
    props: {...}
  }),
  { notes: ` # 我是一級標題 ## 我是二級標題,行首不能有空格,下同 ### 我是三級標題 1. 我是列表1 2. 我是列表2 ` }
 )
複製代碼

效果以下:

notes中使用MarkDown

若是備註一兩句能說描述清楚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 }
);
複製代碼

效果以下:

使用MarkDown文件
是否是有點喜歡上StoryBook了?至少我是這樣,甚至憧憬着本身開發的組件減輕了更多同行的工做量。

更換主題

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的學習和實踐,我以爲它的確不錯,對於組件的開發、測試、文檔化很是方便:

  1. 支持的主流前端框架
  2. 爲組件提供獨立的開發環境
  3. 多種測試場景,全面測試組件
  4. 使用MarkDown編寫備註
  5. 衆多的Addon,方便擴展

這些對於前端開發的工做,提供了很多改進:

  • 避免混亂的重複代碼,提升代碼複用性
  • 測試人員能夠直接測試組件
  • 豐富的Story,所見即所得
  • 組件開發,督促開發者提升自身技能
  • Markdown的文檔,方便展現組件

可是「人無完人」,我在使用StoryBook過程當中,也發現了一些問題:

  1. Addon太多,管理有些混亂
  2. 支持UI框架多,可是有的Andon卻不是全部UI框架都支持,好比info,具體可參見文檔3
  3. 大版本之間變化大,從網上找到的示例代碼比較老,不能用
  4. 不知道是否支持國際化

任何工具都是入門易、深耕難,StoryBook亦是如此,這須要開發人員提高組件化思惟,並結合更多的實踐,才能讓它更好的助力前端開發。

參考文檔

  1. StoryBook for Angular
  2. StoryBook Theme
  3. StoryBook addon對各前端平臺的支持
  4. StoryBook for Angular在線示例
  5. StoryBook引用靜態資源
相關文章
相關標籤/搜索