iT邦幫忙

2021 iThome 鐵人賽

DAY 9
0
Modern Web

前端工程師在工作中的各種實戰技能 (Vue 3)系列 第 9

[Day09] Storybook - What's a story and how to write

Story 是元件呈現狀態的描述,開發者可以為每個元件攥寫多個 Story,也就是說元件可能會因為不同的參數組合而有不同的樣貌,而我們可以透過定義 Story 來將幾個標誌性的用法呈現出來。

我們以 CLI 創建時自動產生的樣本範例 Button.stories.js 為例。

// src/stories/Button.stories.js
...

const Template = (args) => ({
  components: { MyButton },
  setup() {
    return { args };
  },
  template: '<my-button v-bind="args" />',
});

export const Primary = Template.bind({});
Primary.args = {
  primary: true,
  label: 'Button',
};

export const Secondary = Template.bind({});
Secondary.args = {
  label: 'Button',
};

export const Large = Template.bind({});
Large.args = {
  size: 'large',
  label: 'Button',
};

export const Small = Template.bind({});
Small.args = {
  size: 'small',
  label: 'Button',
};

在 Button.stories.js 中定義了 Primary, Secondary, Large 以及 Small,而這每一個都分別代表著 Button 元件的一個 Story,每個 Story 都有一個相應的側邊欄項目,單擊切換時,它會在 Canvas(一個獨立的預覽 iframe)中呈現相對應的 Story 內容。

https://i.imgur.com/mBylE28.gif

Component Story Format

目前官方推薦我們使用 Component Story Format (CSF) (一個基於 ES6 modules 的格式) 的方式攥寫 Story,每一個 CSF 會 default export 出一個元件的基本設定以及 named export 出一至多個元件的 Story 內容。

在 Storybook 支援的眾多框架之中,唯獨 React Native 無法使用 CSF ,所以如果是 React Native 的開發者,只能使用舊版的 storiesOf API來取代,storiesOf()的使用語法可以參考官方提供的 API 文件

https://ithelp.ithome.com.tw/upload/images/20210924/20113487C75w0ebxGz.png

How to write stories

創建 Story 最簡單的方法就是直接定義多個具有不同參數的元件。

import MyButton from './Button.vue';

export default {
  component: MyButton,
  title: 'Example/Button',
}

export const Primary = () => ({
  components: { MyButton },
  template: '<my-button backgroundColor="#ff0" label="Button" />',
})
export const Secondary = () => ({
  components: { MyButton },
  template: '<my-button backgroundColor="#ff0" label="????" />',
})

這樣的寫法對於很少 Story 的元件來說可能沒什麼問題,但對於有許多 Story 可能就會重複很多程式碼。

Args

為了減少重複的程式碼,我們可以定義一個帶有 args 參數的 Template 函式,該 args 參數會 bind 在元件上作為其 props ,接著再透過 Function.prototype.bind() 來讓每一個複製出來的函式可以互不干擾地設定自己的 args。

需注意的是,args 是關鍵字,不能由開發者自由更換參數名稱。

import MyButton from './Button.vue'

export default {
  title: 'Example/Button',
  component: MyButton
}

const Template = (args) => ({
  components: { MyButton },
  setup () {
    return { args }
  },
  template: '<my-button v-bind="args" />',
})

export const Primary = Template.bind({})
Primary.args = {
  primary: true,
  label: 'Button',
}

export const Secondary = Template.bind({})
Secondary.args = {
  label: 'Button',
}
...

此外你也可以運用展開運算符(Spread Operator) 來重複使用定義好的 Story。

export const PrimaryLongName = Template.bind({});

PrimaryLongName.args = {
  ...Primary.args,
  label: 'Primary with a really long name',
}

Component args

args 除了可以在各個 Story 中定義以外,也可以在元件的層級中定義,如此一來這些 args 就會在所有的 Story 起作用,除非被 Story 層級的 args 給覆蓋掉。

import MyButton from './Button.vue'

export default {
  title: 'Example/Button',
  component: MyButton,
	args: {
    primary; true
  }
}

export const Primary = Template.bind({})
Primary.args = {
  label: 'Button',
}

export const PrimaryLongName = Template.bind({});

PrimaryLongName.args = {
  label: 'Primary with a really long name',
}

export const Secondary = Template.bind({})
Secondary.args = {
  Primary: false,
  label: 'Button'
}

參考資料


今天的分享就到這邊,如果大家對我分享的內容有興趣歡迎點擊追蹤 & 訂閱系列文章,如果對內容有任何疑問,或是文章內容有錯誤,都非常歡迎留言討論或指教的!

明天要來分享的是 Storybook 主題的第三篇 Configure story rendering,那我們明天見!


上一篇
[Day08] Storybook - 基本介紹 & 安裝
下一篇
[Day10] Storybook - Configure story rendering
系列文
前端工程師在工作中的各種實戰技能 (Vue 3)30

1 則留言

0
TD
iT邦新手 4 級 ‧ 2021-10-09 15:21:51

最後一個範例程式碼有些排版跑掉了:

export default {
  title: 'Example/Button',
  component: MyButton,
  args: {
    primary; true
  }
}
...
Secondary.args = {
  Primary: false,
  label: 'Button'
}
Mia Yang iT邦新手 5 級 ‧ 2021-10-09 16:48:55 檢舉

TD 修改了,感謝!

我要留言

立即登入留言