Nuxt.jsにVuetify.jsを導入してブログを作る
はじめに
前回記事で、Nuxt.jsでブログを作ってみる。で素のnuxt.jsを触り始めました。 今回はGUIをよりリッチに整えて作っていきたいので、Vuetify.jsを入れて再度作り込んで行きます。 Material Design系のUIが手軽に作れるという触れ込みです。
Vuetify | Material Design Framework
前回記事と同じところまでをまずは作っていくということでさっそく始めましょう。
Nuxt.jsプロジェクトの新規作成(Vuetify.js)
基本的には選択肢を増やすだけです。 UI frameworkに今回は、Vuetify.jsを選択肢、 moduleには、Axiosと、Contentを追加しています。 それ以外は特に特筆する点はないかと思います。
Nuxtはデフォルトで選択できるUI Frrameworkが多くていいですよね。
PS C:\src\Nuxt> npx create-nuxt-app KokoDevVuetyfi
ひとまず設定としてこのようにしました。
create-nuxt-app v3.7.1
✨ Generating Nuxt.js project in KokoDevVuetyfi
? Project name: KokoDevVuetyfi
? Programming language: JavaScript
? Package manager: Yarn
? UI framework: Vuetify.js
? Nuxt.js modules: Axios - Promise based HTTP client, Content - Git-based headless CMS
? Linting tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Static (Static/Jamstack hosting)
? Development tools: jsconfig.json (Recommended for VS Code if you're not using typescript)
? What is your GitHub username? kenpos
? Version control system: Git
既存プロジェクトに追加する場合
今回のブログでは新規インストールでやり直しますが、自前のプロジェクトにVuetify.jsを追加する方法も取れます。
yarn add @nuxtjs/vuetify
nuxt.config.js
上記ファイルをこのように書き換えると良いって公式サイトにも書いてます。
{
buildModules: [
// Simple usage
'@nuxtjs/vuetify',
// With options
['@nuxtjs/vuetify', { /* module options */ }]
]
}
プロジェクトの実行
とりあえずコンソールの指示に従って打ち込みます。
cd .\KokoDevVuetyfi\ | yarn dev
http://localhost:3000/で立ち上げ確認します。
プロジェクトフォルダをVisual Studio Codeで開く
code .
とりあえず、Visual Studio Codeで立ち上げて編集していきましょう。
不要なファイルを削除
componentsの中身は一通り削除します。(後で必要なものを自分で作っていきます。)
rm .\components\*
rm .\static\*
rm .\store\*
rm .\assets\*
タイトルとコンテンツが書かれたヘッダコンポーネントを作成
componentsフォルダにHeader.vueを作成します。
Bottom navigation を参考にアイコンボタン付きのHeaderを作ってみましょう。
Header.vue全体コード
Headerというているが、v-cardタグに記載していきます。 v-cardsコンポーネントの説明はこちらに記載があります。
一部引用します。
パネルから静的画像まであらゆるものに使用できる汎用性の高いコンポーネントです
こんな感じに書きました。
<template>
<header>
<v-card color="basil">
<v-card-title class="text-center justify-center py-6">
<h1 class="font-weight-bold text-h2 basil--text">
心のデブを信じろ
</h1>
</v-card-title>
<v-bottom-navigation v-model="value">
<v-btn value="home" to="/">
<span>Home</span>
<v-icon>mdi-home</v-icon>
</v-btn>
<v-btn value="profile" to="/profile">
<span>Profile</span>
<v-icon>mdi-account</v-icon>
</v-btn>
</v-bottom-navigation>
</v-card>
</header>
</template>
v-button-navigationの中に、v-btnを並べていきます。 v-btnが押されたときには、pagesの中にある*.vueファイルからできるリンクに飛ぶようにしてあります。 例えば、profile.vueがあれば、to=/profileと書くことでリンクに飛ばすことが可能です。
今回は、基から入っていたinspier.vueをprofile.vueにファイル名を変更して作成しています。
v-iconではMaterial icon標準で使える用になっています。 使用できるIconはこちらを参考ください。
index.vue
トップページを作っていきます。 書いてあった内容には参考になる情報が沢山含まれていますが、煩雑なので全部削除します。
<template>
<v-row justify="center" align="center">
<v-col cols="12" sm="8" md="4">
<v-card>
<h2>Title1</h2>
</v-card>
<v-card>
<h2>Title2</h2>
</v-card>
</v-col>
</v-row>
</template>
代わりにこれを書いておきました。
inspier.vue -> profile.vue への書き換え
inspier.vueの名前をprifile.vueに変更します。
中身も、staticフォルダの中身を消したので画像周りは削除しておきましょう。
<template>
<v-row>
<v-col class="text-center">
<blockquote class="blockquote">
“First, solve the problem. Then, write the code.”
<footer>
<small>
<em>—John Johnson</em>
</small>
</footer>
</blockquote>
</v-col>
</v-row>
</template>
全ページを縦断する画面表示を作成
layout/default.vueの編集します。
nuxtのUIを使わないサンプルであれば、.nuxtフォルダ以下に居たファイルと同じ役目をします。 先程作成した、Headerをv-containerに追加しましょう。
<template>
<v-app>
<v-main>
<v-container>
<Header />
<Nuxt />
</v-container>
</v-main>
<v-footer
:absolute="!fixed"
app
>
<span>© {{ new Date().getFullYear() }}</span>
</v-footer>
</v-app>
</template>
実行結果
随分デフォルトファイルから変更しました。
Themeの変更
暗いブログってのはあまり好みではないのでDarkモードから色を変更します。 nuxt.config.jsを編集すうと叶います。
一部抜粋。
// Vuetify module configuration: https://go.nuxtjs.dev/config-vuetify
vuetify: {
customVariables: ['~/assets/variables.scss'],
theme: {
- dark: true,
+ dark: false,
themes: {
dark: {
primary: colors.blue.darken2,
accent: colors.grey.darken3,
secondary: colors.amber.darken3,
info: colors.teal.lighten1,
warning: colors.amber.base,
error: colors.deepOrange.accent4,
success: colors.green.accent3
}
}
}
},
themeの中にあるdarkをfalseにした際には色使いがこのようになります。
小学生のブリーフみたいな真っ白になりましたね。
記事の一覧を作成する
articlesフォルダを作る
pagesとcontentフォルダarticlesというフォルダを作成します。
記事情報の出力準備
_slug.vueを作成します。 nuxt-contentを使って、articlesのフォルダ内の.mdの冒頭タグから情報を引っ張ってきます。
<template>
<article>
<h1>{{articles.title}}</h1>
<p>{{articles.date}}</p>
<p>{{articles.datetimes}}</p>
<nuxt-content :document="articles" />
</article>
</template>
<script>
export default {
async asyncData ({ $content, params }) {
const articles = await $content('articles', params.slug || 'index').fetch()
return { articles }
}
}
</script>
トップページに表示する
index.vueを編集して行きます。
v-cardを使って各記事のタグ情報を書き出して並べていきます v-forでarticlesの中に含まれる要素を取り出していきます。 cols=autoとすることで、ブラウザのサイズに合わせて横に並べる個数を変えてくれるようになります。
各記事のリンクは:to="’/articles/’+b.slug"で指定します。 v-imgタグにはひとまずオンライン上の画像をリンクにしていますが、markdonwのタグから引っ張るようにすれば記事毎に画像を表示するようなこともできます。
<template>
<v-container mt-50 pt-50>
<v-row class="white" style="height: auto;">
<v-col v-for="b in articles" :key="b.slug" cols=auto>
<v-card
max-height="400"
max-width="400"
min-height="400"
min-width="400"
elevation="3"
class="mx-auto"
outlined
:to="'/articles/'+ b.slug"
>
<v-img
class="white--text align-end"
height="200px"
src="https://cdn.vuetifyjs.com/images/cards/docks.jpg"
>
<v-card-title>{{b.title}}</v-card-title>
</v-img>
<v-card-subtitle class="pb-0">
{{b.datetimes}}
</v-card-subtitle>
<v-card-text class="text--primary">
<div>{{b.description}}</div>
</v-card-text>
<v-card-actions>
<v-btn
color="orange"
text
>
Read
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
async asyncData ({ $content }) {
const query = await $content('articles' || 'index').limit(20)
const articles = await query.fetch()
return { articles }
}
}
</script>
記事
contents/articlesフォルダ内に、適当な名前の.mdファイルを作ります。
今回はタグ情報にこういった内容を追加しました。 markdown書く際にatomを使っていて、このプラグインを導入しています。このプラグインで新しい記事を書くと自動で挿入されるのがしたのタグです。 中身はもともとあったファイルを流用しています。
実行結果
ちなみに同じmarkdownファイルをコピーして増やすと記事も増えます。
まとめ
前回と同じところまでVuetify.jsを使って書き換えることができました。 道半ば感はありますが良いんじゃないでしょうか。 今日は子供が早起きなのでここまでです。