iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 20
1
Modern Web

玩轉 Storybook系列 第 20

玩轉 Storybook: Day 20 Construct a screen - Vue

在前面的單元,我們已經完成了開發單一元件Task,也完成了複合元件 TaskList,也把 TaskList 拆分為容器型(TaskList.vue) 及 表現型(PureTaskList.vue),接下來要做的是把元件組合成頁面 - InboxScreen。

元件驅動開發

元件驅動開發 Component-Driven Development(CDD),是指從元件開始向上開發,逐步的擴充及組合元件,到最後完成一個頁面。

Nested container components

在 InboxScreen 除了使用 TaskList,也會在當頁面出問題時呈現錯誤的樣式。InboxScreen 也會拆分成容器型(InboxScreen.vue) 及表現型 (PureInboxScreen.vue)

表現型 PureInboxScreen.vue

表現型會做DOM markup及樣式呈現,如果有 error 就顯示錯誤區塊,否則就呈現 TaskList

<!--src/components/PureInboxScreen.vue-->
<template>
  <div>
    <div class="page lists-show" v-if="error">
      <div class="wrapper-message">
        <span class="icon-face-sad" />
        <div class="title-message">Oh no!</div>
        <div class="subtitle-message">Something went wrong</div>
      </div>
    </div>
    <div class="page lists-show" v-else>
      <nav>
        <h1 class="title-page">
          <span class="title-wrapper">Taskbox</span>
        </h1>
      </nav>
      <task-list />
    </div>
  </div>
</template>

<script>
  import TaskList from './TaskList.vue';

  export default {
    name: 'pure-inbox-screen',
    props: {
      error: {
        type: Boolean,
        default: false,
      },
    },
    components: {
      TaskList,
    },
  };
</script>

容器型 InboxScreen.vue

容器型會做資料及狀態管理,把內容利用props傳給表現型

<!--src/components/InboxScreen.vue-->
<template>
  <div>
    <pure-inbox-screen :error="error" />
  </div>
</template>

<script>
  import PureInboxScreen from './PureInboxScreen';
  import { mapState } from 'vuex';

  export default {
    name: 'inbox-screen',
    components: {
      PureInboxScreen,
    },
    computed: {
      ...mapState(['error']),
    },
  };
</script>

頁面呈現 App.vue

App.vue 使用 InboxScreen.vue (容器型)

<!--src/App.vue-->
<template>
  <div id="app">
    <inbox-screen />
  </div>
</template>

<script>
  import store from './store';
  import InboxScreen from './components/InboxScreen.vue';
  export default {
    name: 'app',
    store,
    components: {
      InboxScreen,
    },
  };
</script>
<style>
  @import "./assets/index.css";
</style>

Stories 使用 表現型元件

PureInboxScreen.stories.js

//src/components/PureInboxScreen.stories.js
import PureInboxScreen from './PureInboxScreen.vue';
export default {
  title: 'PureInboxScreen',
};

// inbox screen default state
export const Default = () => ({
  components: { PureInboxScreen },
  template: `<pure-inbox-screen/>`,
});

// inbox screen error state
export const error = () => ({
  components: { PureInboxScreen },
  template: `<pure-inbox-screen :error="true"/>`,
});

現在Storybook有出現PureInboxScreen的元件清單,但Default Story,還需要把內容傳給它做呈現

Supplying context to stories

//src/components/PureInboxScreen.stories.js
import Vue from 'vue';
import Vuex from 'vuex';
import PureInboxScreen from './PureInboxScreen.vue';
import { action } from '@storybook/addon-actions';
import { defaultTasksData } from './PureTaskList.stories';
Vue.use(Vuex);
export const store = new Vuex.Store({
  state: {
    tasks: defaultTasksData,
  },
  actions: {
    pinTask(context, id) {
      action('pinTask')(id);
    },
    archiveTask(context, id) {
      action('archiveTask')(id);
    },
  },
});
export default {
  title: 'PureInboxScreen',
  excludeStories: /.*store$/,
};
export const Default = () => ({
  components: { PureInboxScreen },
  template: `<pure-inbox-screen/>`,
  store,
});
// tasklist with pinned tasks
export const error = () => ({
  components: { PureInboxScreen },
  template: `<pure-inbox-screen :error="true"/>`,
});

單元測試 使用 表現型元件

小結

本篇修改的程式碼:https://git.io/JUySW

Next

接下來的二個單元就介紹 Angular 元件 CDD 搭配 ngrx 的寫法。

Reference

Construct a screen - Vue


上一篇
玩轉 Storybook: Day 19 Wire in data - Vue & Vuex
下一篇
玩轉 Storybook: Day 21 Wire in data - Angular & ngxs
系列文
玩轉 Storybook30

尚未有邦友留言

立即登入留言