Angular 與 Storybook:元件開發與展示指南
1. Storybook 介紹
1.1 什麼是 Storybook?
Storybook 是一個開源工具,專為 UI 元件的開發和測試而設計。它提供了一個獨立的環境,讓開發者能夠以隔離的方式開發、展示和測試元件,不受主應用程式的影響。
Storybook 的主要特色:
元件隔離:在與應用程式分離的環境中開發元件
互動展示:以互動方式展示元件的各種狀態
自動文檔:自動生成元件文檔,包括 API 說明
豐富的插件生態:支援各種視覺測試、無障礙性檢查等功能
1.2 為什麼使用 Storybook?
使用 Storybook 開發 UI 元件有許多優勢:
提高開發效率:
專注於單一元件開發,不需要啟動整個應用
快速切換元件的不同狀態進行測試
提升元件品質:
確保元件在各種狀態下的行為一致
輕鬆測試邊界情況
改善團隊協作:
為設計師和開發者提供一個共同的參考點
作為可互動的元件文檔,幫助團隊理解元件用法
建立設計系統:
統一管理和展示 UI 元件庫
確保元件在整個應用中的一致性
2. 安裝與設定
2.1 在 Angular 專案中安裝 Storybook
在現有的 Angular 專案中安裝 Storybook:
# 使用 npx 安裝最新版本的 Storybook
npx storybook@latest init
這個命令會自動:
安裝必要的依賴
創建
.storybook
配置資料夾添加需要的 npm scripts
生成一些範例 stories
2.2 Storybook 資料夾結構
安裝後,專案中會新增以下關鍵檔案和資料夾:
.storybook/
├── main.ts # 主要配置文件
├── preview.ts # 全局預覽配置
└── tsconfig.json # TypeScript 配置
src/
└── stories/ # 示例 stories
└── Button.stories.ts # 範例元件的 story
package.json # 新增 storybook 相關的 scripts
2.3 執行 Storybook
安裝後,可以使用以下命令啟動 Storybook:
# 使用 npm script
npm run storybook
# 或使用 ng 指令 (Angular CLI)
ng run your-project-name:storybook
啟動後,Storybook 通常會在 http://localhost:6006 運行,打開瀏覽器即可看到元件展示界面。
3. Storybook 核心配置文件
3.1 main.ts
.storybook/main.ts
是 Storybook 的主要配置文件,用於定義全局設定:
import type { StorybookConfig } from "@storybook/angular";
const config: StorybookConfig = {
// 定義 stories 檔案的位置模式
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
// 添加 Storybook 插件
addons: [
"@storybook/addon-links", // 元件間連結
"@storybook/addon-essentials", // 核心功能插件集
"@storybook/addon-interactions", // 互動測試
"@storybook/addon-a11y", // 無障礙性測試
],
// 框架配置
framework: {
name: "@storybook/angular",
options: {},
},
// 文檔生成配置
docs: {
autodocs: "tag", // 自動為帶有特定標籤的 stories 生成文檔
},
};
export default config;
3.2 preview.ts
.storybook/preview.ts
文件用於設定 stories 的全局預覽行為:
import { applicationConfig, type Preview } from "@storybook/angular";
import { setCompodocJson } from "@storybook/addon-docs/angular";
import docJson from "../documentation.json";
import { provideHttpClient } from "@angular/common/http";
// 設置 Compodoc 生成的文檔
setCompodocJson(docJson);
// 全局預覽配置
const preview: Preview = {
parameters: {
// 控制面板配置
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
// 其他全局參數
backgrounds: {
default: 'light',
values: [
{ name: 'light', value: '#f8f8f8' },
{ name: 'dark', value: '#333333' },
],
},
},
};
// 全局裝飾器 - 提供應用程式配置
export const decorators = [
applicationConfig({
providers: [
provideHttpClient(), // 全局提供 HttpClient
],
}),
];
export default preview;
4. 創建 Stories
4.1 Story 基本結構
Story 是 Storybook 的基本單位,每個 story 代表元件的一種狀態或用例。以下是一個基本的 story 文件結構:
// button.stories.ts
import { Meta, StoryObj } from '@storybook/angular';
import { ButtonComponent } from './button.component';
// Meta 定義了元件的元數據
const meta: Meta<ButtonComponent> = {
title: 'Components/Button', // 導航中顯示的標題路徑
component: ButtonComponent, // 關聯的元件
tags: ['autodocs'], // 標籤,用於自動生成文檔
argTypes: { // 參數類型定義
backgroundColor: { control: 'color' },
size: {
control: { type: 'select' },
options: ['small', 'medium', 'large'],
},
},
// 所有 stories 的默認參數
args: {
label: 'Button',
},
};
export default meta;
// Story 定義
type Story = StoryObj<ButtonComponent>;
// 主要按鈕 story
export const Primary: Story = {
args: {
primary: true,
},
};
// 次要按鈕 story
export const Secondary: Story = {
args: {
primary: false,
},
};
// 大型按鈕 story
export const Large: Story = {
args: {
size: 'large',
},
};
4.2 args 與 argTypes
args
args
是傳遞給元件的參數,用於控制元件的狀態:
// 元件層級的默認 args
args: {
label: 'Click me',
size: 'medium',
},
// Story 層級的 args,會覆蓋元件層級的默認值
export const Small: Story = {
args: {
size: 'small',
label: 'Small button',
},
};
argTypes
argTypes
定義了參數的元數據,如控制器類型、描述等:
argTypes: {
// 使用顏色選擇器
backgroundColor: {
control: 'color',
description: '按鈕背景顏色',
table: {
category: '樣式',
defaultValue: { summary: 'transparent' },
},
},
// 使用下拉選單
size: {
control: { type: 'select' },
options: ['small', 'medium', 'large'],
description: '按鈕大小',
table: {
category: '尺寸',
defaultValue: { summary: 'medium' },
},
},
// 使用開關
disabled: {
control: 'boolean',
description: '是否禁用',
defaultValue: false,
table: {
category: '狀態',
},
},
}
4.3 Actions
Actions 用於監聽和記錄元件觸發的事件:
// 使用 action 函數
import { action } from '@storybook/addon-actions';
const meta: Meta<ButtonComponent> = {
// ...
args: {
onClick: action('button clicked')
}
};
// 或使用 Storybook 7 提供的 fn 函數
import { fn } from '@storybook/test';
const meta: Meta<ButtonComponent> = {
// ...
args: {
onClick: fn()
}
};
5. 高級功能
5.1 元件文檔
Storybook 可以自動生成元件文檔,只需添加 tags: ['autodocs']
到 meta 配置:
const meta: Meta<MyComponent> = {
title: 'Components/MyComponent',
component: MyComponent,
tags: ['autodocs'], // 啟用自動文檔
};
也可以使用 MDX 格式編寫更豐富的文檔:
// MyComponent.mdx
import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs';
import { MyComponent } from './MyComponent';
import * as Stories from './MyComponent.stories';
<Meta of={Stories} />
# MyComponent
這是一個自定義元件的說明。
<Canvas>
<Story of={Stories.Default} />
</Canvas>
## 屬性說明
<ArgsTable of={MyComponent} />
## 使用示例
以下是一個使用示例...
5.2 交互測試
使用 play
函數可以自動化測試元件的交互行為:
import { expect } from '@storybook/jest';
import { userEvent, within } from '@storybook/testing-library';
export const ClickTest: Story = {
args: {
label: 'Click me',
},
play: async ({ canvasElement }) => {
// 獲取 canvas 內的元素
const canvas = within(canvasElement);
// 找到按鈕元素
const button = canvas.getByRole('button', { name: /Click me/i });
// 模擬點擊
await userEvent.click(button);
// 檢查結果
await expect(button).toHaveClass('clicked');
},
};
6. 實用技巧
6.1 全局樣式
在 .storybook/preview.ts
中引入全局樣式:
// 引入應用的全局樣式
import '../src/styles.scss';
const preview: Preview = {
// ...
};
6.2 自定義裝飾器
使用裝飾器包裝 stories 來添加上下文或樣式:
// 全局裝飾器
export const decorators = [
(Story) => ({
template: `
<div style="margin: 2em;">
<story />
</div>
`,
}),
];
// 單個 story 裝飾器
export const WithCustomWrapper: Story = {
decorators: [
(Story) => ({
template: `
<div style="border: 2px dashed red; padding: 1em;">
<story />
</div>
`,
}),
],
};
6.3 動態載入數據
使用 loaders 在 story 渲染前載入數據:
export const WithLoadedData: Story = {
loaders: [
async () => ({
users: await fetch('/api/users').then(r => r.json())
}),
],
render: (args, { loaded: { users } }) => ({
props: {
...args,
users,
},
}),
};
7. 最佳實踐
7.1 組織 Stories
使用一致的命名和分類結構
按功能或模塊組織 stories
考慮使用子目錄來組織複雜元件
// 使用斜線來建立分層結構
const meta: Meta = {
title: 'Design System/Atoms/Button',
};
7.2 測試覆蓋
為每個元件的主要用例和邊界情況創建 stories
使用 play 函數測試互動行為
結合視覺回歸測試工具如 Chromatic
7.3 文檔完善
為每個元件添加清晰的描述
使用 argTypes 提供參數的詳細說明
添加使用示例和最佳實踐說明
8. 常見問題與解決方案
8.1 故障排除
問題:Stories 不顯示在側邊欄
檢查
main.ts
中的stories
路徑是否正確確認 story 文件名稱符合匹配模式
檢查 story 文件中
title
屬性是否設置正確
問題:元件無法渲染
檢查元件導入路徑是否正確
確保所有依賴都已正確提供
檢查控制台錯誤信息
8.2 性能優化
使用動態導入大型元件
優化元件渲染性能
考慮使用 Storybook 的構建優化選項
9. 結語
Storybook 是開發 Angular 元件的強大工具,它不僅提高了開發效率,還能確保元件質量和一致性。通過隔離環境展示和測試元件,團隊可以更快地迭代、溝通和協作。
掌握 Storybook 的基本概念和高級功能,將幫助你建立更強大、更易維護的元件庫,為你的 Angular 應用提供可靠的 UI 基礎。
Last updated