概要
JSフレームワークであるVue.jsでもReactでも、アトミックデザインを採用して実装する案件にアサインすることが多くなってきました。
そこでフロントエンドでの範囲に限られますが、バックエンドから取得したデータを出力するまでの手法として、各テンプレートの構成や処理内容について紐解いていこうと思います。
バージョン環境
vue@2.6.14
ソース構成
App.vue
├ views
└ page.tpl //大元の画面
├ components
├ Heading.tpl //見出しを出力
├ Table.tpl //テーブル全体を出力
└ tableList.tpl //テーブルのリストを出力
└ assets/css
├ style.scss
└ page.scss
画面に出力される大枠のテンプレートは page.tpl
です。
これとヘッダー、フッターなどを組み合わせてページ全体を構成する形になるため、アトミックデザインの「Organisms」にあたります。
その中の構成コンポーネントとしてテーブルを出力する Table.tpl
、その中のリストを出力する tableList
などが存在します。
中身のボリュームはものによって変わるので、アトミックデザインの「Atoms」や「Molecules」にあたります。
また、スタイライズについては共通のものを使用し、 style.scss
で全体管理をしつつ各画面ごとにスタイルシートを適用する形のイメージです。
(今回のテンプレートの場合は page.scss
)
画面のベース構成
まず大元となる page.tpl
を見ていきます。
<template>
<!-- テンプレートの中身を記述 -->
<Title type="h2">
見出し
</Title>
<Table
:items="items.listItems"
/>
</template>
<script>
// テンプレートで呼び出すコンポーネントを指定
import Table from '@/components/Table';
import Title from '@/components/Title';
export default {
data() {
return {
//初期値、データ型を設定する
items: {
listItems: [],
}
};
},
components: {
// テンプレート内で呼び出すコンポーネントを指定
Table
},
created() {
// テンプレートが呼び出されたタイミングで実行するファンクション
this.getListItems();
},
computed: {
// 子コンポーネントに返り値を渡す際のファンクション
},
methods: {
// テンプレート内で実行するファンクションの内容を定義
getListItems() {
this.items.listItems = [APIで取得したデータ];
},
}
};
</script>
<template>
<h2 v-if="type == 'h2'">
<slot></slot>
</h2>
<h3 v-else-if="type == 'h3'">
<slot></slot>
</h3>
<h4 v-else-if="type == 'h4'">
<slot></slot>
</h4>
</template>
<script>
props: {
// 親から受け取るプロパティの型定義
type: {
type: String,
required: false
}
}
</script>
pageでは2つのコンポーネントを呼び出します。
見出しを出力する Title
、テーブルを出力する Table
です。
Titleコンポーネントについては記述したテキストを元にh2〜h4の見出しを出力します。
どのタグを出すかは、親テンプレートで指定したプロパティ type
を参照する形になっています。
ミニマムなコンポーネントに対して親側で要素を設計する場合は、子供側で slot
を記述することで構成にあった出力をすることができます。
Tableについては :items
プロパティを設定していますが、これはcreatedのタイミングでmethodsの getListItems
によりAPIデータが取得され、dataに入ったものを参照しているという流れになります。
なおこの次にここで取得したデータをtableList
で一覧表示することになるのですが、tableListはpageと直接的な連携を行うわけではないのでここではimportなどの記述が必要ありません。
Tableを介してtableListがデータを取得する流れができていればいいというわけです。
テーブル部分の構成
<template>
<table>
<tr>
<th>項目1</th>
<th>項目2</th>
<th>項目3</th>
<th>項目4</th>
</tr>
<tableList
v-for="item in items"
:key="item.id"
:item="item"
/>
</table>
</template>
<script>
import tableList from '@/components/tableList';
export default {
props: {
items: {
type: Array,
required: true
}
},
components: {
tableList
}
};
</script>
<template>
<table>
<tr>
<th>{item.data1}</th>
<th>{item.data2}</th>
<th>{item.data3}</th>
<th>{item.data4}</th>
</tr>
</table>
</template>
<script>
export default {
props: {
item: {
type: Object,
required: true
}
}
};
</script>
まずTable
では、page
で取得されたデータリスト「listItems」をitems
という配列で継承しています。
このitemsはtableList
への継承データとなり、tableListをimportした状態でv-for
でループ出力させる構造になっています。
表示順は:key
プロパティでの指定が可能で、今回はAPIデータに含まれるitem.id
を指定しています。
次にtableList
側ではそのデータをpropsで受け取り、4つある項目にそれぞれの値を出力している形になります。
ここのdata1
やdata2
といった値は、データの大元であるAPIデータ側の構成に準拠した名前となります。