こんにちは、フロントエンドエンジニアのライダーです。
今回は「Nuxt de Portfolio」連載のチャプター3となります。
【Ch.2】プロジェクトを作成する【Nuxt de Portfolio】
前回の記事で作成したコンポーネントをもっと便利に活用していきましょう!
振り返り
ここまでは Nuxt を学習しつつ、ページとレイアウトを中心に、サイト全体をざっくり作ってきました。ディレクトリ構成はこんな感じになっていると思います。
components/
common/TheHeader.vue
common/TheFooter.vue
pages/
index.vue
about/index.vue
layouts/
default.vue
error.vue
CSSはベースをグローバルに登録して、コンポーネントは scoped
を活用してマークアップを進めました。一方で冗長になってしまった部分があります。
@import "~assets/scss/variables"
が各コンポーネントに出現した.article-body {}
が各コンポーネントに出現したh2 {}
が各コンポーネントに出現した
基本的にどれも、「頻出するものを、ひとつ(一箇所)にまとめる」方針で問題なさそうですね。
SCSS変数を全コンポーネントで使えるようにする
@import "~assets/scss/variables"
が各コンポーネントに出現し、記述が非常に面倒です。ここでは、どのコンポーネントでも使えるように、https://github.com/nuxt-community/style-resources-module を使いグローバルへ登録します。
npm install --save-dev @nuxtjs/style-resources
nuxt.config.js
/*
** Nuxt.js modules
*/
modules: ['@nuxtjs/style-resources'],
styleResources: {
scss: ['~/assets/scss/_variables.scss']
}
こうすることで、 _variables.scss
はたびたびインポートせずとも、どこでも使えるようになりました。今回は存在しませんが、 _mixin.scss
なども登録すると面倒が減っていいですね。
グローバルで使えるようになったので、各コンポーネントで記述していた
@import "~assets/scss/variables"
は、すべて削除していきましょう。
修正・追加・削除等があったファイル
- [修正]
layouts/error.vue
- [修正]
pages/about/index.vue
- [修正]
pages/index.vue
- [修正]
nuxt.config.js
- [修正]
components/common/TheFooter.vue
- [修正]
components/common/TheHeader.vue
ArticleBody コンポーネントを作成する
次は、 <slot>
を活用し、このクラスを持ったコンポーネントを外に切り出していきます。
components/common/ArticleBody.vue
を作成してください。
<template>
<div class="article-body">
<slot></slot>
</div>
</template>
<style scoped lang="scss">
.article-body {
h3 {
font-size: 20px;
margin: 30px 0 20px;
}
p {
line-height: 1.75;
+ p {
margin-top: 20px;
}
a {
color: $color-blue;
}
}
ul {
list-style: circle;
margin-top: 20px;
margin-left: 20px;
li {
&:nth-of-type(n+2) {
margin-top: 0.5em;
}
}
}
img {
max-width: 100%;
}
}
</style>
<slot> とは?
今回、コンポーネントとして共通化したい部分は外枠(つまり <div class=“article-body”> )であり、中身はコンポーネントの呼び出し元によって変わってきます(記事の中身はサイト全体で同じではないですよね)。
そんなときに、呼び出される共通コンポーネント(今回の ArticleBody )に <slot>をもたせておくと、呼び出し元から <slot> へ挿入することができます。
具体的には、<slot> をもつ ArticleBody に対し、ArticleBodyを呼び出すページコンポーネントが記事内容にあたるHTMLを挿入している部分になります。
ArticleBody コンポーネントを使う
この ArticleBody
コンポーネントを pages/index.vue に組み込みます。コンポーネントの使い方は、TheHeader, TheFooter を使ったときと同様です。
pages/index.vue
<template>
<div class="page-index">
<section class="about">
<h2>夏目漱石</h2>
<ArticleBody>
<img src="~/assets/images/portrait.png" alt="夏目漱石">
<p>日本の小説家、評論家、英文学者。本名、夏目 金之助(なつめ きんのすけ)。江戸の牛込馬場下横町(現在の東京都新宿区喜久井町)出身。俳号は愚陀仏。詳細は<a href="<https://ja.wikipedia.org/wiki/夏目漱石>" target="_blank">ウィキペディア</a>を。</p>
</ArticleBody>
</section>
<section class="works">
<h2>代表作</h2>
<ArticleBody>
<p>『吾輩は猫である』(1905年)がデビュー作である。</p>
<ul>
<li>『吾輩は猫である』(1905年)</li>
<li>『坊っちゃん』(1906年)</li>
<li>『草枕』(1906年)</li>
<li>『三四郎』(1908年)</li>
</ul>
</ArticleBody>
</section>
</div>
</template>
<script>
import ArticleBody from '~/components/common/ArticleBody';
export default {
components: {
ArticleBody
}
}
</script>
<style scoped lang="scss">
.about,
.works {
h2 { ... }
}
/* ここにあった .article-body を削除 */
</style>
新たに、コンポーネントを使うための処理を追加します。CSSでは、実際のスタイルは pages/index.vue
ではなく、 components/common/ArticleBody.vue
がもつようになるため、
.article-body { ... }
は削除しておきます。
テンプレート内、 <div class="article-body">
だった部分を <ArticleBody>
へ変更します。閉じタグの方も変更を忘れずに。
今はこれを、 pages/index.vue
で行いましたが、 pages/about.vue
、layouts/error.vue
でも同様のことを行います。
下記が置き換えの手順です。
- ページ/レイアウトコンポーネントのスタイルから
.article-body {}
を削除する ArticleBody
をscript
でインポートし、components へ登録するdiv.article-body
をArticleBody
へ置き換える
すると、いままで各コンポーネントで記述して冗長になっていた部分が、ひとつのコンポーネントとしてシンプルで扱いやすくなりました。
修正・追加・削除等があったファイル
- [追加]
components/common/ArticleBody.vue
- [修正]
layouts/error.vue
- [修正]
pages/about/index.vue
- [修正]
pages/index.vue
.section-title を作成する
h2 {
...
&::after { ... }
}
コンポーネントの切り出し方法は学んだので、今度は直接CSSにグローバルで登録してみましょう。
assets/scss/_section-title.scss
を作成します。
.section-title {
display: flex;
align-items: center;
margin: 50px 0 30px;
font-size: 30px;
&::after {
content: '';
display: block;
flex: 1;
height: 1px;
margin-left: 10px;
background-color: $color-black;
}
}
また、各コンポーネントで、クラス名無しだった h2
に、クラスを付与し、スタイルから h2 {}
を削除します。
<h2 class="section-title"></h2>
そのあと、 assets/scss/style.scss
で、作成したファイルをインポートします。
@charset "utf-8";
@import '_variables';
@import '_base';
@import '_section-title';
こうすることで、またひとつ冗長な部分が減りました。
全体的にみても、かなりすっきりしています。ほとんど共通のスタイルを利用しているため、 <style>
自体が必要なくなったコンポーネントばかりですね。
error.vue の例
<template>
<div class="layout-error">
<section class="error">
<h2 class="section-title">404</h2>
<ArticleBody>
<h3>名前はまだ無い</h3>
<p>アクセスされたページは存在しないか、すでに削除されています。</p>
</ArticleBody>
</section>
</div>
</template>
見事、テンプレートだけが残り、スタイルはすべて共通化されています。
修正・追加・削除等があったページ
- [追加]
assets/scss/_section-title.scss
- [修正]
layouts/error.vue
- [修正]
pages/about/index.vue
- [修正]
pages/index.vue
- [修正]
assets/scss/style.scss
おわりに
これでコンポーネントをすっきり整理することができましたね。次回はいよいよ、最終調整ののち Netlify へデプロイし、サイトを公開していきます。お楽しみに!
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。