昨天後來在看效果時,有發現過渡動畫的元素已經完全超出卡片組件的範圍了,這個不是我們想要的效果
理想中的效果是要在卡片組件中完成,不能超出範圍
這裡提供兩種方式解決超出範圍的問題
可以在卡片組件的CSS屬性加上 overflow: hidden
,將超出組件的部分隱藏:
加上後就可以達到不超過卡片組件的過渡動畫效果!!
<v-card style="overflow: hidden;">
...
</v-card>
雖然第一種很簡單就能解決,但我們不用它xD
我們用第二種解法,在卡片組件中加上 loading
,參考Vuetify v-card API:
<v-card :loading="card.loading">
...
</v-card>
data加上控制開關:
data() {
return {
card: {
...
loading: false,
},
...
};
},
這個屬性很有趣,雖然他是控制進度條的顯示
但是在進度條顯示時,卡片組件本身會多一個class .v-card--loading
:
.v-card--loading {
overflow: hidden;
overflow-x: hidden;
overflow-y: hidden;
}
看到了嗎? 其中就包含第一種方法使用的 overflow: hidden
了~
也就是說加上 loading
可以同時達成進度條顯示及過渡動畫溢出隱藏的效果!!
進度條的 開啟 的時機在路由每次發生變化時觸發,也就是 watch $route
監聽路由變化事件:
watch: {
$route: {
handler: function(to, from) {
...
this.card.loading = true;
...
}
}
}
進度條的 關閉 比較複雜,要在「下一個頁面已經建立完成」之後才能觸發
這樣可以在發生錯誤時進度條還是維持顯示的狀態,避免造成使用者操作上錯誤認知
而控制 關閉 的部份就會寫在子分頁中,並且使用 .sync
+ $emit
保持雙向溝通
將 loading 傳入子分頁:
<router-view
:loading.sync="card.loading"
></router-view>
子分頁接收 loading:
//KeyinUser.vue
export default {
name: "KeyinUser",
props: ["loading"],
}
以 KeyinUser.vue 為例,其他子分頁如 KeyinPswd.vue、ChooseUser.vue、VerifyUser.vue 都是相同的設定
再來很重要的一步,監聽 loading 值
如果loading值存在而且是 true
則設定1秒後改為 false
,時間可以自行調整但操作上要保持良好流暢度
//KeyinUser.vue
watch: {
loading: {
handler(newValue, oldValue) {
if (newValue) {
setTimeout(() => {
this.$emit("update:loading", false);
}, 1000);
}
},
immediate: true,
},
},
到這邊就完成進度條的控制囉!!
來看看畫面~
應該有發現雖然過渡動畫元素沒有超過卡片組件,而且也有進度條的效果了,但是整體非常不和協,連LOGO標題都跟著位移了,還有錄影錄不出來的部分,整個卡片組件內容在切換頁面時會跳針...
這個問題我花了一天半查原因...
最後終於發現原來是卡片組件的 autofocus
屬性惹的禍
把這個屬性移除就正常了,推測是因為過渡元素還沒顯示出來就聚焦導致畫面偏移,但會發生衝突的原因我沒有深入探討,有興趣的人可以研究看看xD
來看看目前的畫面~
卡片組件的 autofocus
拿掉解決了衝突的問題,但我們還是需要這個效果怎麼辦?
還記得在表單驗證時我們用了 $refs
抓到表單元件後呼叫手動驗證的方法嗎?
在這裡,可以利用它再次幫我們抓到文字輸入框,並呼叫聚焦(focus)的方法
文字輸入框加上屬性 ref
並給它一個命名:
//KeyinUser.vue
<v-text-field
ref="eleAccountId"
...
></v-text-field>
以 KeyinUser.vue 為例,同理可套在 KeyinPswd.vue 上
聚焦方法的觸發時機可以寫在監聽 loading 的地方,當 loading 消失時來觸發:
//KeyinUser.vue
watch: {
loading: {
handler(newValue, oldValue) {
if (newValue) {
setTimeout(() => {
this.$emit("update:loading", false);
}, 1000);
} else {
this.$refs.eleAccountId.focus();
}
},
immediate: true,
},
},
這段意義為: 進入頁面後,觸發監聽事件(因為immediate: true),這時判斷 loading = true
,所以跑1秒後改變為 false
的程式碼,而1秒後再次觸發監聽事件,這時就會跑文字輸入框聚焦(focus)方法
來看看目前的畫面~
看起來順暢多了!!
先來看一段我跟過渡動畫拚手速的畫面xD
有發現嗎? 我的手速可媲美加藤...(咳咳)
手速不是重點,有發現過渡動畫還沒結束就被我截斷了嗎? 這是蠻不好的使用者體驗
好的使用者體驗是讓過渡動畫完整呈現後,才能繼續下一步操作
而為了避免發生有人跟我一樣手速超快的問題,這裡使用了 Vuetify-Overlays 遮罩層組件
把遮罩層加進卡片組件中:
<v-card ...>
<div ...>
...
<v-overlay
:absolute="card.overlay.absolute"
:opacity="card.overlay.opacity"
:value="card.loading"
:color="card.overlay.color"
></v-overlay>
</div>
</v-card>
對應的data:
data() {
return {
card: {
...,
overlay: {
absolute: true,
opacity: 0.3,
color: "#FFF",
},
},
};
},
加上遮罩層之後,就算加藤鷹之手也沒辦法破解它xD
今日重點:
到這邊整體專案就100%完成囉!!
有需要改進或是任何意見建議歡迎下面留言~