今回達成すること
今回はログイン後のトップページにプロジェクト一覧を表示します。
1人のユーザーは複数のプロジェクトを持つデータベース設計を想定して、ユーザーが持つプロジェクト一覧を表示します。
なおプロジェクトは、データベース構築までを予定していませんので、Nuxt.js側で仮作成したのもを表示していきます。
完成イメージ
Vuexにプロジェクトを用意する
まずは仮表示するプロジェクトを用意します。
プロジェクトはVuexで管理する前提とし、state
に用意します。
front/store/index.js
export const state = () => ({
loggedIn: true,
styles: {
beforeLogin: {
appBarHeight: 56
}
},
// 追加
current: {
project: null
},
projects: [
{ id: 1, name: 'MyProject01', updatedAt: '2020-04-01T12:00:00+09:00' },
{ id: 2, name: 'MyProject02', updatedAt: '2020-04-05T12:00:00+09:00' },
{ id: 3, name: 'MyProject03', updatedAt: '2020-04-03T12:00:00+09:00' },
{ id: 4, name: 'MyProject04', updatedAt: '2020-04-04T12:00:00+09:00' },
{ id: 5, name: 'MyProject05', updatedAt: '2020-04-01T12:00:00+09:00' }
]
// ここまで
})
current.project
... 現在選択中のプロジェクトを保管する変数となる。
トップページにプロジェクト一覧を表示する
用意したプロジェクト一覧は
「最近更新したプロジェクト順」で表示したいので、computed
内で更新日時順に並び替えます。
front/pages/index.vue
<template>
<div>
<div
v-for="(p, i) in recentProjects"
:key="i"
>
{{ p.name }}
{{ p.updatedAt }}
</div>
</div>
</template>
<script>
export default {
layout ({ store }) {
return store.state.loggedIn ? 'loggedIn' : 'welcome'
},
computed: {
recentProjects () {
const copyProjects = Array.from(this.$store.state.projects)
return copyProjects.sort((a, b) => {
if (a.updatedAt > b.updatedAt) { return -1 }
if (a.updatedAt < b.updatedAt) { return 1 }
return 0
})
}
}
}
</script>
Vuexの値をsortする時の注意点
Vuexに用意した変数(state
内の値)は、mutations
内でしか変更できません。
JavaScriptのsort
メソッドは破壊的なので、そのままVuexの値を並びかえすると「mutations
内で変更してね!」と言うエラーを吐きます。
そこで、Array.from()
で一度配列をコピーし、そのコピーした配列を並び替えすることでこのエラーを回避します。
確認してみよう
コンテナを起動して、http://localhost:8080/ にアクセスしてください。
用意したプロジェクトが更新日時順に並び替えられていますね。
アイキャッチ画像を表示する
アイキャッチ画像は、ここのサイトの画像を一枚使用します。
適当なpngファイルをダウンロードしてください。
ダウンロードした画像は
クレジット無しで商用利用可能なので本番環境でも利用できます。
本番環境での使用は、必ずご自身でライセンスの確認を取ってください。
assets以下に画像を保管する
ダウンロードした画像を保管するディレクトリを作成します。
「assets/images」以下に「loggedIn」ディレクトリを作成しましょう。
root $ mkdir front/assets/images/loggedIn
この「loggedIn」ディレクトリ内に、ダウンロードした
front/assets/images
├── loggedIn
│ └── home.png
├── member1.png
├── member2.png
└── member3.png
トップページから画像を読み込み表示する
それでは<v-img>
を使って画像を表示しましょう。
HTML部分はまるっと書き換えてください。
front/pages/index.vue
<template>
<div id="logged-in-home">
<v-parallax>
<v-img
:src="homeImg"
alt="homeImg"
:aspect-ratio="16/9"
gradient="to top right, rgba(100,115,201,.33), rgba(25,32,72,.7)"
>
<v-container
fill-height
>
<v-row
justify="center"
align="center"
>
<v-col
cols="12"
:sm="container.sm"
:md="container.md"
>
<v-card-title class="white--text">
最近のプロジェクト
</v-card-title>
<v-divider dark />
<v-row
align="center"
>
<v-col
cols="12"
:sm="card.sm"
:md="card.md"
>
<v-btn
block
:height="card.height"
:elevation="card.elevation"
>
<div>
<v-icon
size="24"
color="myblue"
class="my-2"
>
mdi-plus
</v-icon>
<div class="caption myblue--text">
プロジェクトを追加
</div>
</div>
</v-btn>
</v-col>
</v-row>
</v-col>
</v-row>
</v-container>
</v-img>
</v-parallax>
</div>
</template>
<script>
// 追加
import homeImg from '~/assets/images/loggedIn/home.png'
export default {
layout ({ store }) {
return store.state.loggedIn ? 'loggedIn' : 'welcome'
},
// data () 追加
data () {
return {
homeImg,
container: {
sm: 10,
md: 8
},
card: {
sm: 6,
md: 4,
height: 120,
elevation: 4
}
}
},
computed: {
recentProjects () {
const copyProjects = Array.from(this.$store.state.projects)
return copyProjects.sort((a, b) => {
if (a.updatedAt > b.updatedAt) { return -1 }
if (a.updatedAt < b.updatedAt) { return 1 }
return 0
})
}
}
}
</script>
<!-- css 追加 -->
<style lang="scss">
#logged-in-home {
.v-parallax__content {
padding: 0;
}
}
</style>
import homeImg ...
... 「assets」ディレクトリ以下に保存した画像を使用するには、import
して、data()
内で変数に代入する必要があります。
いい感じに表示されました。
日付のフォーマット変換メソッドを作成する
プロジェクト一覧を表示する前に、日付のフォーマット変換メソッドを用意します。
これはアプリ内全体で使用するので、
myInject.jsはこちらの記事で作成しました。
front/plugins/myInject.js
class MyInject {
...
// 追加
// 日時フォーマット変換
format (date) {
const dateTimeFormat = new Intl.DateTimeFormat(
'ja', { dateStyle: 'medium', timeStyle: 'short' }
)
return dateTimeFormat.format(new Date(date))
}
}
...
-
Intl.DateTimeFormat
... JavaScriptの日時フォーマット変換用メソッド。
プロジェクトリンクを生成するメソッドを作成する
プロジェクトの個別ページへ遷移するリンクには、各プロジェクトを判断するパラメーターを埋め込まなければなりません。
毎回パラメータを記述するのは面倒なので、メソッド化します。
同じく
front/plugins/myInject.js
class MyInject {
...
// 日時フォーマット変換
format (date) {
const dateTimeFormat = new Intl.DateTimeFormat(
'ja', { dateStyle: 'medium', timeStyle: 'short' }
)
return dateTimeFormat.format(new Date(date))
}
// 追加
// プロジェクトリンク
projectLinkTo (id, name = 'project-id-dashboard') {
return { name, params: { id } }
}
}
...
-
name = 'project-id-dashboard'
... 第二引数にはデフォルト値を設定している。プロジェクトの
id
だけを引数に渡した場合、自動的にダッシュボードリンクへ遷移するようにしています。
最近のプロジェクトをカードで表示する
直近で更新したプロジェクト2つをカードとして表示します。
このカードはアイキャッチ画像の上に載せます。
作成したformat
とprojectLintTo
メソッドも使用します。
front/pages/index.vue
...
</v-col>
<!-- 追加 -->
<v-col
v-for="(project, i) in recentProjects.slice(0, 2)"
:key="`card-project-${i}`"
cols="12"
:sm="card.sm"
:md="card.md"
>
<v-card
block
:height="card.height"
:elevation="card.elevation"
:to="$my.projectLinkTo(project.id)"
class="v-btn text-capitalize"
>
<v-card-title class="pb-1 d-block text-truncate">
{{ project.name }}
</v-card-title>
<v-card-text class="caption">
<v-icon size="14">
mdi-update
</v-icon>
{{ $my.format(project.updatedAt) }}
</v-card-text>
</v-card>
</v-col>
<!-- ここまで -->
</v-row>
</v-col>
</v-row>
</v-container>
</v-img>
</v-parallax>
</div>
</template>
...
OK!!
リンク先ページは作成していないので、クリックしてもエラーになりますが、更新日時はちゃんと変換されました。
全てのプロジェクトをテーブルで表示する
Vuetifyの<v-data-table>
を使って、プロジェクト一覧を表示します。
テーブルはアイキャッチ画像下に設置します。
...
</v-parallax>
<!-- 追加 -->
<v-container>
<v-row justify="center">
<v-col
cols="12"
:sm="container.sm"
:md="container.md"
>
<v-card-title>
全てのプロジェクト
</v-card-title>
<v-divider class="mb-4" />
<v-data-table
:headers="tableHeaders"
:items="recentProjects"
item-key="id"
hide-default-footer
>
<template v-slot:item.name="{ item }">
<nuxt-link
:to="$my.projectLinkTo(item.id)"
class="text-decoration-none"
>
{{ item.name }}
</nuxt-link>
</template>
<template v-slot:item.updatedAt="{ item }">
{{ $my.format(item.updatedAt) }}
</template>
</v-data-table>
</v-col>
</v-row>
</v-container>
<!-- ここまで -->
</div>
</template>
<script>
import homeImg from '~/assets/images/loggedIn/home.png'
export default {
...
data () {
return {
...
// 追加
tableHeaders: [
{
text: '名前',
value: 'name'
},
{
text: '更新日',
width: 150,
value: 'updatedAt'
}
]
}
},
...
}
</script>
-
hide-default-footer
...v-data-table
のデフォルトで表示されるフッター部分を非表示にする。 -
v-slot:item.<オブジェクトキー>="{ item }"
... テーブルの値を個別に編集したい場合に使用するスロット。名前にリンクを、更新日にフォーマット変換メソッドを追加するために使用しています。
OK!!!!テーブルが表示されました。
コミットしよう
お昼です。コミットしてご飯にしましょう。
root $ cd front
front $ git add -A && git commit -m "created_top_page_layout" && cd ..
root $
まとめ
今回はログイン後のトップページを構築しました。
実はこのデザイン、Firebaseを参考にしました。
が!あそこまで綺麗なデザインを作り込むことができませんでした。
うーん。Firebaseの劣化版ですね。😟
次回は?
プロジェクトを表示する、「ダッシュボード」のレイアウトを構築します。
次で終わるぞぉぉぉぉぉぉ!!
(Go!!↓Next)