Help us understand the problem. What is going on with this article?

Nuxt.js(v2.6.x)やっておきたい設定:その3/3|コンポーネントフィアルの管理方法とloading・各種トランジションの設定

More than 1 year has passed since last update.

本稿は「Nuxt.js(v2.6.x)やっておきたい設定シリーズ」の第3段です。


「Nuxt.jsやっておきたい設定:その3/3」として、コンテンツ詳細の作成に入る前に決めておきたい「コンポーネントファイルの管理方法」と「loading・各種トランジションの設定」をまとめる。
プロジェクトチームの趣味趣向に合わせて変更を検討すべきことだが、一つの基準があったほうが話が進みやすいと思う。

すこしでも手助けになれば。

コンポーネントファイルの管理方法

コンポーネントファイルのファイル名の先頭に、-ignorePrefix)を必ずつける。すると、ファイル名にかかわらずなんのファイルか判断することができる。もちろんわかりやすい名前にしたほうが良いのだが…なかなか難しいので。

詳細は、nuxt.jsにおけるコンポーネントの規約(案)その2:ignorePrefixプロパティ版を読んでほしい。

設定内容だけ記載する。

componentsディレクトリ内のファイルを一括登録&呼び出し

plugins経由で登録を行うことで、どこからでも呼び出せるようになるのでcomponents.jsを作成する。

plugins/components.js
import Vue from 'vue'

import UButton from '~/components/-ui-button'
import UFigure from '~/components/-ui-figure'
import MHeading from '~/components/-main-heading'

Vue.mixin({
  components: {
    UButton,
    UFigure,
    MHeading,
  }
})

components.jsをnuxt.confing.jsに登録

nuxt.config.js
module.exports = {
  plugins: [
    { src: '~plugins/components' },
    ...
  ],
}

毎回importしなくても呼び出せるようになる。

test.vue
<template lang="pug">
div
  m-heading ページ名
  u-button(to="/") ボタン
</template>

OK。

トランジションの種類

Nuxt.jsが基本機能を設定、また、自作して設置しておく。ある程度のインタラクティブなサイトを構築できる想定だ。具体的には以下5つ。

  • 初回アクセス時のローディング(自作)
  • loading(Nuxt.js基本機能)
  • ページ推移トランジション(Nuxt.js基本機能)
  • ページ推移時のコンポーネントのトランジション(自作)
  • パーツのトランジション(参考までに)

初回アクセス時のローディング(自作)

どれだけチューンナップしても初回アクセス時の表示が遅くなることがある。ならば、できるだけユーザーに楽しんでもらうことに方向を切り替えるのも一つの手だ。

ならば、初めから仕込んでおく。

layout内に-first-loading.vueを設置

まず気づいただろうか…。ファイル名の先頭に-(ignorePrefix)がついてるだけで、コンポーネントファイルを作成してるとわかる。これが、規約の素晴らしさ。そしてlayout内に設置したということは、もちろんlayout内のdifult.vueに追加していくこととなる。

layout/-first-loading.vue
<template lang="pug">
div
  .loading(:class="{ 'is-finish': dataLoadFinish }")
    p loading...
</template>

<script>
export default {
  data() {
    return {
      dataLoadFinish: false
    }
  },
  mounted() {
    window.addEventListener('load', () => {
      this.dataLoadFinish = true
    })
  }
}
</script>

<style lang="scss" scoped>
.loading {
  position: fixed;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100vw;
  height: 100vh;
  background: $primary;
  color: $white;
  &.is-finish {
    transition: opacity 1s, z-index 0s 1.01s;
    opacity: 0;
    z-index: -1;
  }
}
</style>

difult.vueに-first-loading.vueを追加

layout/difult.vue
<template lang="pug">
div.layout
  firstLoading
  nuxt
</template>

<script>
import firstLoading from './-first-loading'
export default {
  components: {
    firstLoading,
  }
}
</script>

<style lang="scss" scoped>
.layout {
  position: relative;
}
</style>

以上だ。ある程度なれている人ならば、そんなに難しくないはず。

loading(Nuxt.js基本機能)

Nuxt.jsの基本機能のままシンプルでよい(と思う)。なぜならばprefetch機能が充実したNuxt.jsなら殆ど表示されない。すばらしい。

APIの呼び出し方法に注意しつつ、色味を変更する程度でいいだろう。

nuxt.config.js
module.exports = {
  ...
  loading: { color: '#0A428C' },
}

mouted内でAPIを呼び出ししている場合は注意

loadingが表示されるのは、体外がAPIを呼び出すときだ。syncDataやfetchで指定している場合は、ディフォルトのloading設定がうまくやってくれる。

しかし…

mouted内でAPIを呼び出しする場合にはひと手間が必要。

pages/loading-test-in-mounted.vue
<template lang="pug">
div
  u-button(to="/") index
  p(v-if="!json") 呼び出し中
  pre(v-else) {{json}}
</template>

<script>
export default {
  loading: false, // ←これ忘れがちなので入れる。
  data() {
    return {
      json: null
    }
  },
  async mounted() {
    this.json = await this.$axios.$get('https://randomuser.me/api/')
    this.$nuxt.$loading.finish()
  }
}
</script>

参考:公式サイト- loading プロパティ

ちゃんと呼び出されるまでAPIの呼び出しが完了するまでローディングが続いてくれる。

OK。

ページ推移トランジション(Nuxt.js基本機能)

次はページ推移時のトランジション。これもシンプルでいいと思う。

まずは、トランジションscssを作成

AOSを参考にトランジションscssを作成。

asetts/css/transition/index.scss
.fade {
  &-leave-active {
    transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
  }
  &-leave-to {
    opacity: 0;
  }
  &-enter {
    opacity: 0;
  }
  &-enter-active {
    transition: all .6s ease;
  }
}

.fade-up {
  &-leave-active {
    transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
  }
  &-leave-to {
    transform: translateY(-10px);
    opacity: 0;
  }
  &-enter {
    transform: translateY(10px);
    opacity: 0;
  }
  &-enter-active {
    transition: all .6s ease;
  }
}

.fade-down {
  &-leave-active {
    transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
  }
  &-leave-to {
    transform: translateY(10px);
    opacity: 0;
  }
  &-enter {
    transform: translateY(-10px);
    opacity: 0;
  }
  &-enter-active {
    transition: all .6s ease;
  }
}

.fade-right {
  &-leave-active {
    transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
  }
  &-leave-to {
    transform: translateX(-10px);
    opacity: 0;
  }
  &-enter {
    transform: translateX(10px);
    opacity: 0;
  }
  &-enter-active {
    transition: all .6s ease;
  }
}

.fade-left {
  &-leave-active {
    transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
  }
  &-leave-to {
    transform: translateX(10px);
    opacity: 0;
  }
  &-enter {
    transform: translateX(-10px);
    opacity: 0;
  }
  &-enter-active {
    transition: all .6s ease;
  }
}

.zoom-in {
  &-leave-active {
    transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
  }
  &-leave-to {
    transform: scale(.9);
    opacity: 0;
  }
  &-enter {
    transform: scale(.9);
    opacity: 0;
  }
  &-enter-active {
    transition: all .6s ease;
  }
}

nuxt.config.jsから呼び出す。

nuxt.config.js
module.exports = {
  css: [
    ...
    // Original
    '~/assets/css/transition/index.scss',
  ],
}

使いたいトランジションを選ぶ。

ページ推移用のトランジションは2種類あることに注意したい。

  • transition(通常のページ推移時のトランジション)
  • layoutTransition(layoutの変更があった場合のトランジション)

両方とも設定しておく。

nuxt.config.js
module.exports = {
  ...
  transition: {
    name: 'fade-left',
    mode: 'out-in'
  },
  layoutTransition: {
    name: 'fade-right',
    mode: 'out-in'
  },
}

動作確認

npm run dev

OK。

ページ推移時のコンポーネントのトランジション(自作)

ページ移動時のフックの設定
を参考に、ページの変更を検知できるようにする。

sotreの設置

当時よりnuxt.jsが優秀になっているのでモジュールモードでシンプルに作成できる。

store/pages.js
// state
export const state = () => ({
  page: 'index'
})

// mutations
export const mutations = {
  updatePage(state, pageName) {
    state.page = pageName
  }
}

middlewareの設置

ここは、当時から変わんないかな。

middleware/pages.js
export default function (context) {
  // go tell the store to update the page
  context.store.commit('pages/updatePage', context.route.name)
}

middlewareを読み込ませる

nuxt.config.jsに読み込ませる。

nuxt.config.js
module.exports = {
  router: {
    ...
    middleware: 'pages',
  },
}

-main-heading.vueで試してみる。

components/-main-heading.vue
<template lang="pug">
div
  transition(name="zoom-in" mode="out-in")
    .m-heading(v-show="enter")
      p {{ page }}-
      slot
</template>

<script>
export default {
  data() {
    return {
      enter: false
    }
  },
  computed: {
    page() {
      return this.$store.state.pages.page
    }
  },
  watch: {
    page() {
      this.enter = false
    }
  },
  mounted() {
    this.enter = true
  },
}
</script>

<style lang="scss" scoped>
.m-heading {
  background-color: $primary;
  display: flex;
  align-items: center;
  justify-content: center;
  color: $white;
  width: 100%;
  height: 200px;
}
</style>
pages/test.vue
<template lang="pug">
div
  m-heading ページ名
  u-button(to="/") indexへ
</template>

OK。

ページ推移トランジションと同じタイミングで、コンポーネントのトランジションが動いた。
あとは、transition(name="xxx")を変えて遊ぶだけ。かなり細かいところまでトランジションが調整できるようになった。

パーツのトランジション(参考までに)

ラスト。

vue本来のトランジションの使い方を3つほど復習する。

  • name属性を変更してトランジションの動作を変える。
  • mode属性を変更してトランジションの動作を整える。
  • v-for使っているときは、transition-groupを使う。mode="out-in"が効かないので工夫する。
pages/sample.vue
<template lang="pug">
div
  m-heading sample
  .content
    .section
      u-button(to="/") index
      hr
      h2 name属性を変更してトランジションの動作を変える。
      h3 fade-up
      transition(name="fade-up" mode="out-in")
        p(v-if="show1" key="1") {{show1}}
        p(v-else key="2") {{show1}}
      button.button(@click="show1 = !show1") toggle show
      h3 zoom-in
      transition(name="zoom-in" mode="out-in")
          p(v-if="show2" key="1") {{show2}}
          p(v-else key="2") {{show2}}
      button.button(@click="show2 = !show2") toggle show
      hr
      h2 mode属性を変更してトランジションの動作を整える。
      h3 mode="out-in" 有り
      div
        transition(name="fade-left" mode="out-in")
          p(v-if="show3" key="1") {{show3}}
          p(v-else key="2") {{show3}}
        button.button(@click="show3 = !show3") toggle show
      h3 mode="out-in" なし
      transition(name="fade-left")
          p(v-if="show3" key="1") {{show3}}
          p(v-else key="2") {{show3}}
      button.button(@click="show3 = !show3") toggle show
      hr
      h2 v-for使っているときは、`transition-group`を使う。`mode="out-in"`が効かないので工夫する。
      button.button(@click="show4 = !show4") toggle show
      transition-group.group(name="fade-left" tag="div")
        div.loading(v-if="!json" key="loading") 読み込み中だよ
        div.loading(v-if="show4 === false" key="stoping") 準備できたよ
        div(v-else key="wrapper")
          div(v-for="(v, k, i) in json.results[0]" :key="i")
            div {{ i }}
            pre {{ v }}
            br
</template>

<script>
export default {
  loading: false, // ←これ忘れがちなので入れる。
  data() {
    return {
      json: null,
      show1: false,
      show2: false,
      show3: false,
      show4: false,
      show5: false,
    }
  },
  async mounted() {
    this.json = await this.$axios.$get('https://randomuser.me/api/')
    this.$nuxt.$loading.finish()
  }
}
</script>

<style lang="scss" scoped>
.group {
  position: relative;
}
.loading {
  position: absolute;
}
</style>

お疲れ様でした。

これで、Nuxt.js(v2.6.x)やっておきたい設定 1〜3が完了。どのプロジェクトでも使える内容になってった…はず。

今まで設定してきた内容は、少し手を加えつつGitHubにアップした。

ということは?



amiTemplate-nuxt爆誕。(GitHubページへ)

amishiro
5年近く作っていた自作テンプレートから離れて、最近はnuxtで開発してる。フロントエンドの未来は明るい。寂しいのでフォロープリーズ。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした