目標
鐵人文即將進入尾聲
這篇將網站的功能收尾
會將前面做過的東西算是總複習再做一遍
我們這次要做的功能是畫面Loading的模擬
同時也會把一些金言佳句放在載入畫面上
大略會像下圖排版
加載畫面除了作為網站歡迎頁面外
在加載完成後
我也想讓它出現「金言佳句或一些心靈雞湯」
步驟
1.
同樣從畫面規劃開始
因為從Supabase取資料一定會一些延遲時間
所以需要做加載畫面
下圖是加載前的資料
下圖則為加載後的資料 同時呈現金言佳句的文章
底下是我們這次要用的Bootstrap元件-Modal
首先我們來看官方文件中的Demo
它實際上就是彈出視窗
但是我們要的是點背景不會關閉 而是按下X按鈕才關閉
雖然它有提供靜態背景的架構
不過我們還是需要另外調整
先回到父組件APP.vue
在template最上方加上以下程式架構
<template>
<!-- Loading Modal -->
<div v-if="modalOpen" class="modal fade show d-block bg-dark" tabindex="-1" >
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content text-center">
<div class="modal-header">
<h5 class="modal-title">歡迎來到關卡查詢網站</h5>
<!-- X 按鈕:僅當全部載入完成後才顯示 -->
<button
type="button" class="btn-close"
@click="modalOpen = false">
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-6 bg-primary text-start"></div>
<div class="col-6 bg-warning d-flex flex-column justify-content-center align-items-center">
<div >
<div class="spinner-border text-primary" role="status">
</div>
<p class="mt-2">資料載入中...</p>
</div>
<div>文字文字文字</div>
<div class="mt-auto ms-auto">來源</div>
</div>
<div>
<div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
//...以下略
</template>
現在畫面如下圖
依照剛才線稿的規劃
將資料載入動畫和文字內容放上
接著補上我們在Day24存的頭像
同時在script增加以下程式架構
就和我們之前讀取圖片網址做法相同
其中supportSettingImgUrl
屬性
要另外再補上沒有設置頭像時 預設的圖片
<script setup>
//....中間略
import { useLocalStorageRef } from "./useLocalStorageRef.js"
const favoriteSupportSettingList = useLocalStorageRef("favoriteSupportSettingList");
const images = require.context('@/assets/Fairy', false, /\.(png|jpg)$/)
const supportSettingImgUrl = computed(() => {
return favoriteSupportSettingList.value.length != 0
? images(`./${favoriteSupportSettingList.value["eventNo"]}.png`)
: images("./0000.jpg") ;
})
</script>
接下來
我們要控制關閉按鈕來關閉Modal元件
但是,關閉按鈕會在什麼時候出現呢?
所以會有以下情況判斷
關閉按鈕出現的條件是
全部子組件取Supabase的資料完畢 才會出現
由於B、D、S組件在初始載入時要連Supabase API
所以流程圖會像下面這樣
當子組件都取完資料後 告訴父組件完成了
父組件控制關閉按鈕的顯示
回到父組件這邊
我們預計的規劃如下
B組件載入完成=>emit傳回true=>LoadingB改為true
D組件載入完成=>emit傳回true=>LoadingD改為true
S組件載入完成=>emit傳回true=>LoadingS改為true
我們將script補上幾段showClose
是關閉按鈕的顯示
判斷loadingState裡的屬性是否都為true
<script setup>
const modalOpen = ref(true);
const loadingState = ref({
LoadingB : false,
LoadingD : false,
LoadingS : false,
})
const showClose = computed(() => {
return loadingState.value.LoadingB &&
loadingState.value.LoadingD &&
loadingState.value.LoadingS ;
})
</script>
同樣在template也補上幾個屬性
比較重要的是補上相對應的v-if
屬性
去控制關閉按鈕、Modal視窗的顯示
接下來,我們要做的就是捕捉子組件載入的狀況
先在B組件做試試看
我們載入B組件的屬性 多加上下圖這個紅框
來捕捉B組件傳過來的資料
再來到B組件
這邊加一個emit
別忘記也要定義emit
<script setup>
const emit = defineEmits(["response","responseBF","responseBDisplay","responseBR","loading"]);
onMounted(async () => {
const { data, error } = await supabase
.from("action_event")
.select("*")
if (error) {
console.error(error);
} else {
result.value = data;
emit("responseBF", result.value);
emit("responseBR", result.value);
setTimeout(() => {emit("loading", true)}, 3000)
}
});
</script>
如下圖紅框 是修改的地方
由於資料取得的速度約略1秒左右 可能看不出差異
所以利用setTimeout特性
在3秒後emit送出「B組件取好資料了」的訊息
如下圖 取完資料後再等3秒出現關閉按鈕
接著我們把其他子組件也做相同的emit傳送
然後把金言佳句、心靈雞湯的句子也放進來
下圖資料這是在網路上抓的
我們在父組件template補上以下程式架構
同樣初次就載入
我們用getRandomSentence
屬性
去取隨機的資料
<script setup>
const result = ref([]);
const getRandomSentence = computed(() => {
const randomNumber = Math.floor(Math.random() * (result.value.length));
return result.value[randomNumber]
})
onMounted(async () => { //初次就載入資料
const { data, error } = await supabase
.from("dailygold")
.select("*")
if (error) {
console.error(error);
} else {
result.value = data;
}
});
</script>
template也跟著稍微調整如下圖
這一頁result讀取Supabase
而getRandomSentence的資料來源於result
一開始result沒有資料 它也會是空的
我們在這邊用v-if
去判斷result
這邊有個重點是
如果v-if
為false
Vue在渲染時 就不會建立這個虛擬DOM節點
即使getRandomSentence這個時候沒有東西
但因為這個節點一開始本來就不存在
裡面這層的插值表達式{{getRandomSentence}}
不會被求值
也就不會導致程式報錯的問題
下圖就是我們這次的成果
使用者每次打開網路都會顯示不同句子
按下關閉按鈕 就回到我們網站了
這篇做了網站程式架構的收尾
讓它已經有了初步的雛型
接下來最後幾篇,我們要做網站上傳的準備工作
讓外部網路也能連到。
備註
1.
剛才有提到
因為圖片的引入是看Assets底下的檔案
所以由於父組件和子組件檔案放置路徑不同
引入的路徑也會和子組件有差異
其他段的引入也會需要注意到哦
因為Supabase有效能與安全考量
預設資料在1000筆
無論你條件是什麼 都只會回1000筆
所以如果需要一次取超過1000筆的資料
我們可以到API Setting這邊做設定