Nuxt Loading Component: Customize the Progress Bar

Nuxt
Loading
progress bar

在開始前,請先看過一遍Nuxt Loading官方文件


如果沒有要調整progress bar的位置,可直接在nuxt.config.js內設定loading的property就好


(2.x版官方提供的設定值如下圖)


本文主要說明Hamsterism所使用的客製化loading component如何實作


在切換頁面時,會發現在頂端黑色nav bar下方會快速地跑過progress bar動畫


為了讓progress bar固定在nav bar下方,我選擇採自製loading component的方式


直接上component程式碼

<template>
  <div
    v-if="status"
    :class="{ successful: success, failed: failure }"
    class="loading-bar"
    :style="barOpacity"
  >
    <div
      :class="{ failed: failure }"
      class="loading-bar-shadow"
      :style="barOpacity"
    ></div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      error: false,
      success: false,
      failure: false,
    }
  },
  computed: {
    barOpacity() {
      return {
        opacity: this.status ? '1' : '0',
      }
    },
    status() {
      return this.$store.getters['isLoading']
    },
  },
  methods: {
    start() {
      this.$store.commit('unload')
      this.success = false
      this.failure = false
      this.$store.commit('load')
    },
    finish() {
      this.success = true
      this.$store.dispatch('unload')
    },
    fail(error) {
      this.error = error
      this.failure = true
    },
  },
}
</script>
<style lang="scss" scoped>
.loading-bar {
  display: block;
  position: fixed;
  top: 3rem;
  left: 0;
  right: 0;
  height: 5px;
  z-index: 49;
  transition: all 0.3s linear;
  background-color: $hamsterism-btn-color-primary;
  overflow: hidden;
  animation: loading 5s ease-in-out;
  animation-fill-mode: both;
  &.failed {
    background-color: $hamsterism-btn-color-danger-dark;
    width: 100%;
    animation: none;
  }
  &.successful {
    width: 100%;
    animation: none;
  }
  &-shadow {
    display: block;
    position: absolute;
    right: 0;
    width: 100px;
    height: 3px;
    box-shadow: 1px 0px 10px $hamsterism-btn-color-primary;
    transform: rotate(3deg) translate(0px, -1px);
    &.failed {
      box-shadow: 1px 0px 10px $hamsterism-btn-color-danger-dark;
    }
  }
}
@keyframes loading {
  0% {
    width: 0;
  }
  100% {
    width: 100%;
  }
}
</style>


關鍵method

官方提供四個客製化時會用到的method:start()、finish()、fail(error)、increase(num)


前三個開始、結束、失敗很直觀沒問題


最後一項increase(num)由於缺少範例,所以我不知道該怎用,直接放棄Ovo


因為放棄了控制一次increase多少進度的功能,所以整個載入以固定時長的動畫實作


動畫設計很簡單,從0%到100%,控制width變化


時長我設為5s,超過五秒以上的載入會卡在100%的意思


早於5s完成的話,Nuxt會觸發finish(),在scss的&.successful控制使width變為100%


同理,若載入失敗,Nuxt會觸發fail(),在scss的&.failed控制width變為100%且變色



Store管理loading狀態

看官網文件會發現,它的loading變數寫在component的data


原先我也是用這寫法,但發現頁面切換上animation狀態變超怪...


由於搞不懂Nuxt呼叫loading component的變數記憶情況


我改將loading的狀態統一由store(vuex)來管理,最沒爭議Ovo


直接寫在~/store/index.js (你要另外創一個loading.js也可以)

export const state = () => ({
  loading: false,
})
export const getters = {
  isLoading(state) {
    return state.loading
  },
}
export const mutations = {
  load(state) {
    state.loading = true
  },
  unload(state) {
    state.loading = false
  },
}
export const actions = {
  unload({ commit }) {
    setTimeout(() => {
      commit('unload')
    }, 300)
  },
}


更改狀態的mutation很簡單,需要注意的關鍵點在action unload()


以setTimeout延遲300ms才發出unload的狀態變更,來配合 transition: all 0.3s linear;


不然progress bar會提前消失唷!


至於固定特定位置、變更顏色、變更粗細等,都在scss的 .loading-bar 內客製


修改nuxt.config.js

最後一步,在nuxt.config.js告訴Nuxt你的loading要用自己做出來的組件

(component位置就看你放哪兒)

export default {
  //...
  loading: '~/components/ui/LoadingBar.vue',
  //...
}


完成!👏👏👏


© 2021 Hamsterism. All rights reserved github