在開始前,請先看過一遍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',
//...
}
完成!👏👏👏