SPA開発 8. ログイン周りのレイアウト設計 #02
2019年11月29日に公開

【Nuxt.js】ウェルカムページのレイアウト構築【sassの導入】

今回達成すること

今回は、ログイン前のトップページに表示されるウェルカムページを作成していきます。

以下の手順で進めていきます。

  1. アプリ全体で利用する、共通タイトルの設定
  2. ログイン前のヘッダー(header.vue)の編集
  3. Nuxt.jsにsassを導入
  4. 新規会員登録ページ(signup.vue)を作成
  5. ログイン前後、共通で利用するフッター(footer.vue)の編集
  6. ログイン前のレイアウトファイル(home.vue)の編集

なお、最終的にトップページはこのようになります。

完成イメージ

2019-11-28 21-14-31

2019-11-28 21-14-46

筆者のhome.vueサンプルコードは、下記目次に記載しています。

#筆者のhome.vue

作業に移る前に

今回の記事は全てNuxt.js上での作業となります。

ターミナルは、Rails内のNuxt.jsプロジェクト(筆者の場合、myapp/frontend)に移動しておいてください。

froutend $ # ここに移動しておく

共通タイトルの設定

まず、アプリで使用する共通タイトルを設定していきます。

ヘッダーに表示したり、フッターのコピーライトに表示するアプリ名のことですね。

今のタイトルはどこから表示されているか?

2019-11-28 13-38-14

現状、筆者の場合では「frontend」という名前がページタイトルとして表示されています。

これはNuxt.jsの作成時に決めたプロジェクト名が反映されています。

どこで設定されているかというと、package.json内のnameというプロパティです。

frontend/package.json
{
  "name": "frontend",
	...
}

ここのnameを、nuxt.config.jsheadプロパティでタイトルとして設定しています。

frontend/nuxt.config.js
const config = {
  mode: 'spa',
  head: {
    title: process.env.npm_package_name || '',
    ...

つまり、package.jsonで好きな名前に書き換えて、nuxt.config.js内で取得すれば良いってことですね。

共通タイトルを書き換えて表示する

仕組みがわかったところで、package.json内の共通タイトルを書き換えましょう。

frontend/package.json
{
  "name": "demoApp", // 自由な名前でOK
	...
}

クライアント側で使えるようにenvプロパティを登録

今のままコンポーネント内でprocess.env.npm_package_nameを利用しようとしても、空の値が返されます。

何故かというと、process.envの中身はサーバー側の値であり、クライアント(ブラウザ)側からは読み込めないためです。

そこで、サーバー側の値をクライアント側でも利用できるよう、nuxt.config.jsenvプロパティを登録します。

frontend/nuxt.config.js
const config = {
	...
  
  // 追記
  env: {
    APP_NAME: process.env.npm_package_name
  }

}

この設定により、クライアント側でprocess.env.APP_NAMEという環境変数が利用できるようになりました。

共通タイトルを確認しましょう

ログイン前のヘッダーコンポーネント、header.vueを以下のように書き換えてください。

frontend/components/shared/header.vue
<template>
  <div>
    {{ appName }}
  </div>
</template>

<script>
export default {
  data: () => ({
    appName: process.env.APP_NAME
  })
}
</script>

package.jsonで指定したアプリ名が表示されます。

2019-11-28 14-18-23

ログイン前のヘッダー「header.vue」を編集する

さて、次はこんな感じ↓にログイン前のヘッダーを編集していきます。

完成イメージ

2019-11-28 17-24-47

componentsディレクトリ内のheader.vueを開いてください。

frontend/components/shared/header.vue
<template>
  <div>
    <v-app-bar
      elevation="1"
    >
      <v-toolbar-title>
        <nuxt-link
          to="/"
        >
          {{ appName }}
        </nuxt-link>
      </v-toolbar-title>

      <v-spacer />

      <v-toolbar-items
        v-for="(link, i) in links"
        :key="i"
      >
        <v-btn
          :to="link.to"
          text
          class="font-weight-bold"
        >
          {{ link.title }}
        </v-btn>
      </v-toolbar-items>
    </v-app-bar>
  </div>
</template>

<script>
export default {
  data: () => ({
    appName: process.env.APP_NAME,
    links: [
      { title: '新規会員', to: '/signup' },
      { title: 'ログイン', to: '/login' }
    ]
  })
}
</script>
  • v-app-bar

    Vuetifyのv-toolbarでも同じヘッダーを作成できますが、今回はv-app-barを採用しました。

    v-app-barは、様々なスクロールイベントを付与することができます。

    App bars - Vuetify

ただ…ちょっとアプリ名がリンク色に染まってブサイクですね…。

2019-11-28 16-28-31

Nuxt.jsにsassを導入する

sassを導入してオリジナルのCSSクラスを作成しましょう。

今回は公式のインストール方法に従ってsassを導入します。

API: css プロパティ - Nuxt.js

1. node-sass と sass-loaderをインストールする

ターミナルより、sass実行に必要なモジュールをインストールします。

frontend $ yarn add node-sass sass-loader

2. main.scssファイルの作成

assets直下にcssディレクトリと、main.scssファイルを作成します。

 frontend % mkdir assets/css && touch assets/css/main.scss

assetsディレクトリの構成は以下のようになります。

assets
├── README.md
└── css
    └── main.scss

3. nuxt.config.jsにCSSファイルを登録

続いてnuxt.config.jsにmain.scssをメインCSSファイルとして登録します。

frontend/nuxt.config.js
const config = {
	...
  
  css: [
    '@/assets/css/main.scss'	// 追記
  ],
  
}

以上で設定は完了です。

これでsassが利用できるようになりました。

main.scssにオリジナルクラスを作成する

main.scssにリンクカラーを黒にするクラスを作成し、ヘッダーアプリ名の色を変更します。

frontend/assets/css/main.scss
$black: rgba(0, 0, 0, 0.87);

// commons //////////////////////////
body {
  word-wrap: break-word;
  overflow-wrap: break-word;
}
a.link-black {
  color: $black !important;
  text-decoration: none;
}
  • $black: rgba(0, 0, 0, 0.87);

    $blackには、Vuetifyのブラックと一致する色を指定しています。

header.vueにクラスを付け加える

作成したlink-blackクラスをアプリ名に付け加えましょう。

frontend/components/shared/header.vue
<template>
  ...
  <nuxt-link
    to="/"
    class="link-black font-weight-bold" <!-- 追記 -->
  >
    {{ appName }}
  </nuxt-link>

よし、これでアプリ名がブサイクではなくなりました!

2019-11-28 16-46-47

新規会員登録ページ「signup.vue」を作成する

今のままヘッダーの「新規会員」をクリックすると、ページが無いためエラーになります。

そこでsignup.vueファイルを作成します。

frontend $ touch pages/signup.vue

作成したsignup.vueを仮編集しておきましょう。

frontend/pages/signup.vue
<template>
  <div>
    新規会員登録ページ
  </div>
</template>

<script>
export default {
}
</script>

これにて「header.vue」は完成です

以上でログイン前のheader.vueは完成です。

2019-11-28 17-24-47

共通のフッター「footer.vue」を編集する

続いてfooter.vueの編集です。

完成イメージ

2019-11-28 18-16-37

frontend/components/shared/footer.vue
<template>
  <v-footer
    padless
  >
    <v-col
      class="text-center"
      cols="12"
    >
      <div class="body-2">
        &copy;{{ copyRightYear }} — <strong>{{ appName }}</strong>
      </div>
    </v-col>
  </v-footer>
</template>

<script>
export default {
  data: () => ({
    appName: process.env.APP_NAME
  }),
  computed: {
    copyRightYear () {
      const start = 2019
      const now = new Date().getFullYear()
      return (start === now) ? start : `${start} - ${now}`
    }
  }
}
</script>
  • copyRightYear ()

    現在の年度とアプリ制作年度を比較して、コピーライトの表記を自動化しています。

    2019年の場合 => 「©2019 — demoApp」

    2020年の場合 => 「©2019 - 2020 — demoApp」

OK!完成イメージ通りのフッターが作成できましたね。

最後。レイアウトファイル「home.vue」を編集する

layputsディレクトリ内に作成したhome.vueは、ログイン前のウェルカムページになります。

よくwebアプリのトップページにある「ようこそ」や「アプリの説明」を表示するページのことです。

<v-content>タグ内に、自由にコンテンツを作成してください。

frontend/layouts/home.vue
<template>
  <v-app>
    <my-header />
    <v-content>
     <!-- ここに自由に追記 -->
    </v-content>
    <my-footer />
  </v-app>
</template>

<script>
import myHeader from '~/components/shared/header.vue'
import myFooter from '~/components/shared/footer.vue'

export default {
  components: {
    myHeader,
    myFooter
  },
  data: () => ({
    appName: process.env.APP_NAME
  })
}
</script>
  • <v-content>

    大切なのは、この<v-content>タグの中にメインコンテンツを書くということです。

    もしこのタグで囲まない場合、コンテンツの高さが足りない時にフッターが上がってきます。

    これはVuetifyのレイアウトの仕組みによるものです。

    Application service — Vuetify.js

v-contentタグで囲まない場合の悪い例

2019-11-28 20-56-41

本番環境にpushしておきましょう

さて、home.vueの編集が完了したら、Railsプロジェクトに戻ってHerokuにPushしましょう。

frontend $ cd ../
myapp $ git add -A
myapp $ git commit -m "welcome_page_layouts"
myapp $ git checkout master
myapp $ git merge login_layouting
myapp $ git push
myapp $ git push heroku

pushが完了したら元のレイアウトブランチに戻っておきます。

myapp $ git checkout login_layouting
myapp $ git branch                  
* login_layouting
  master

まとめ

さて、今回の学んだポイントをおさらいします。

  • アプリの共通タイトルはpackage.jsonnameプロパティで管理する。
  • サーバーサイドとフロントエンドで環境変数を共有したい場合は、nuxt.config.jsenvに登録する。
  • Nuxt.jsにsassを導入する時は、node-sasssass-loader モジュールをインストールする。
  • メインコンテンツは、<v-content>タグで囲む。(Vuetifyの場合)

以上となります。

お疲れでした!(長い戦いだった。。。)

さて、次回は?

さてさて、次回「新規会員登録ページ」のレイアウト構築と、メールアドレス、パスワードの入力フォームの導入を行います。

どうぞ、お楽しみに!

筆者のhome.vue

筆者のサンプルコードです。

frontend/layouts/home.vue
<template>
  <v-app>
    <my-header />
    <v-content>
      <v-parallax
        dark
        src="https://cdn.vuetifyjs.com/images/backgrounds/vbanner.jpg"
      >
        <v-row
          align="center"
          justify="center"
        >
          <v-col
            class="text-center"
            cols="12"
            sm="8"
          >
            <h1 class="display-1 mb-4">
              ようこそ!{{ appName }}へ
            </h1>

            <v-list-item
              href="https://blog.cloud-acct.com/categories/spa"
              target="_blank"
              rel="noopener noreferrer"
            >
              <v-list-item-content>
                <h2 class="subtitle-1 font-weight-medium white--text">
                  このアプリの作り方を見る
                </h2>
              </v-list-item-content>
            </v-list-item>
          </v-col>
        </v-row>
      </v-parallax>

      <v-container>
        <v-row
          justify="center"
        >
          <v-col
            class="text-center"
            cols="12"
          >
            <div>
              {{ appName }}では以下の技術を採用しています。
            </div>
          </v-col>

          <v-col
            v-for="(item, i) in cardItems"
            :key="i"
            class="text-center"
            cols="12"
            :sm="12 / cardItems.length"
          >
            <v-avatar
              :color="item.color"
              :size="(600 / cardItems.length) - 30"
            >
              <span class="white--text display-1">
                {{ item.name }}
              </span>
            </v-avatar>

            <v-card
              flat
              color="transparent"
            >
              <v-card-title class="justify-center">
                {{ item.name }} {{ item.version }}
              </v-card-title>
              <v-card-text>
                {{ item.description }}
              </v-card-text>
            </v-card>
          </v-col>

          <v-col
            class="text-center"
            cols="12"
          >
            <div>
              このアプリの作り方は、チュートリアル形式で公開されています。
            </div>
            <a
              href="https://blog.cloud-acct.com/categories/spa"
              target="_blank"
              rel="noopener noreferrer"
            >
              このアプリの作り方を見る
            </a>
          </v-col>
        </v-row>
      </v-container>
    </v-content>
    <my-footer />
  </v-app>
</template>

<script>
import myHeader from '~/components/shared/header.vue'
import myFooter from '~/components/shared/footer.vue'

export default {
  components: {
    myHeader,
    myFooter
  },
  data: () => ({
    appName: process.env.APP_NAME,
    cardItems: [
      {
        name: 'Rails',
        color: '#CC3C33',
        version: '6.0.0',
        description: 'サーバーサイドにRails APIモードを採用'
      },
      {
        name: 'Nuxt.js',
        color: '#00C550',
        version: '2.10.2',
        description: 'フロントエンドにNuxt.js SPAモードを採用'
      },
      {
        name: 'Vuetify',
        color: '#2271C6',
        version: '2.1.9',
        description: 'UIフレームワーク'
      }
    ]
  })
}
</script>
現在、カテゴリー「Rails apiとNuxt.jsでSPA開発」のデモアプリを構築中です。記事になるまでもう少々のお時間が必要です。ブログの更新が止まって申し訳ありません。デモアプリの進捗状況は こちらの記事 で随時お伝えしてまいります。
スポンサー広告
次の記事はこちらです
SPA開発
今日のTweet
スポンサー広告