一、載入中
二、轉場
三、動畫
四、總結
當我們在處理非同步的需求,中間會有一個等待時間
在等待的過程中,我們可以在Quasar使用幾個方式實現
1. Loading Plugin (全域Loading)
Loading is a feature that you can use to display an overlay with a spinner on top of your App’s content to inform the user that a background operation is taking place. No need to add complex logic within your Pages for global background operations.
https://quasar.dev/quasar-plugins/loading#Loading-API
官方範例示意:
<template>
<div class="q-pa-md">
<q-btn color="purple" @click="showLoading" label="Show Loading" />
</div>
</template>
<script>
export default {
methods: {
showLoading () {
this.$q.loading.show()
// hiding in 2s
this.timer = setTimeout(() => {
this.$q.loading.hide()
this.timer = void 0
}, 2000)
}
},
beforeDestroy () {
if (this.timer !== void 0) {
clearTimeout(this.timer)
this.$q.loading.hide()
}
}
}
</script>
2. QAjax Bar、LoadingBar (全域Loading)
可以在頁面裡面使用QAjax Bar元件
使用ref觸發元件的start()和stop()
QAjaxBar is a component which displays a loading bar (like Youtube) whenever an Ajax call (regardless of Ajax library used) is in progress. It can be manually triggered as well.
https://quasar.dev/vue-components/ajax-bar
<template>
<div class="q-pa-md">
<q-ajax-bar
ref="bar"
position="top"
color="grey-10"
size="10px"
skip-hijack
/>
<q-btn color="primary" label="Trigger" @click="trigger" />
</div>
</template>
<script>
export default {
methods: {
// we manually trigger it (this is not needed if we
// don't skip Ajax calls hijacking)
trigger () {
const bar = this.$refs.bar
bar.start()
this.timer = setTimeout(() => {
if (this.$refs.bar) {
this.$refs.bar.stop()
}
}, Math.random() * 3000 + 1000)
}
}
}
</script>
或者,你也可以使用LoadingBar 觸發全域的QAjax Bar
The Quasar LoadingBar plugin offers an easy way to set up your app with a QAjaxBar in case you don’t want to handle a QAjaxBar component yourself.
https://quasar.dev/quasar-plugins/loading-bar#LoadingBar-API
<template>
<div class="q-pa-md">
<q-ajax-bar
ref="bar"
position="bottom"
color="accent"
size="10px"
skip-hijack
/>
<q-btn color="primary" label="Trigger" @click="trigger" />
</div>
</template>
<script>
export default {
methods: {
showLoading () {
this.$q.loadingBar.setDefaults({
color: 'grey-10',
size: '15px',
position: 'top'
})
this.$q.loadingBar.start()
// hiding in 2s
this.timer = setTimeout(() => {
this.$q.loadingBar.stop()
this.timer = void 0
}, 2000)
}
},
beforeDestroy () {
if (this.timer !== void 0) {
clearTimeout(this.timer)
this.$q.loadingBar.stop()
}
}
}
</script>
3. 元件的loding屬性狀態 (區域Loading)
有些元件本身有loading的屬性狀態可以使用
QBtn
當QBtn的loading的屬性為true,觸發載入狀態官方的寫法蠻糙的
<template>
<div class="q-pa-md q-gutter-sm">
<q-btn :loading="loading1" color="secondary" @click="simulateProgress(1)" label="Button" />
<q-btn :loading="loading2" color="red" @click="simulateProgress(2)">
Button
<template v-slot:loading>
Loading...
</template>
</q-btn>
<q-btn :loading="loading3" color="purple" @click="simulateProgress(3)">
Button
<template v-slot:loading>
<q-spinner-radio />
</template>
</q-btn>
<q-btn :loading="loading4" color="primary" @click="simulateProgress(4)" style="width: 150px">
Button
<template v-slot:loading>
<q-spinner-hourglass class="on-left" />
Loading...
</template>
</q-btn>
<br>
<q-btn round :loading="loading5" color="brown" @click="simulateProgress(5)" icon="camera_front">
<template v-slot:loading>
<q-spinner-facebook />
</template>
</q-btn>
<q-btn round :loading="loading6" color="black" @click="simulateProgress(6)" icon="camera_rear">
<template v-slot:loading>
<q-spinner-gears />
</template>
</q-btn>
<br>
<q-btn :loading="progress" color="primary" @click="progress = true">
Controlled from outside
<template v-slot:loading>
<q-spinner-radio class="on-left" />
Click "Stop" Button
</template>
</q-btn>
<q-btn :disable="!progress" color="negative" @click="progress = false" label="Stop" />
</div>
</template>
<script>
export default {
data () {
return {
loading1: false,
loading2: false,
loading3: false,
loading4: false,
loading5: false,
loading6: false,
progress: false
}
},
methods: {
simulateProgress (number) {
// we set loading state
this[`loading${number}`] = true
// simulate a delay
setTimeout(() => {
// we're done, we reset loading state
this[`loading${number}`] = false
}, 3000)
}
}
}
</script>
QTable
<template>
<div class="q-pa-md">
<q-toggle v-model="loading" label="Loading state" class="q-mb-md" />
<q-table
title="Treats"
:data="data"
:columns="columns"
color="primary"
row-key="name"
:loading="loading"
/>
</div>
</template>
<script>
export default {
data () {
return {
loading: false,
columns: [
...
],
data: [
...
]
}
}
}
</script>
在某一個情況下,元件顯示或隱藏的轉場效果
Quasar 可以使用 QIntersection 包住要套用轉場效果的元件
The QIntersection component is essentially a wrapper over the Intersection directive with the added benefit that it handles the state by itself (does not require you to add it and handle it manually) and can optionally have a show/hide transition as well.
https://s8.gifyu.com/images/06ccf8e10b513489f1.gif
QIntersection 對於舊瀏覽器支援度不高,
如果需要支援舊瀏覽器,可以使用 polyfill package
Not all browsers support the Intersection Observer API. Most modern browsers do, but other browsers, like IE 11, do not. If you need to support older browsers, you can install and import (into a boot file) the official W3C polyfill
https://quasar.dev/vue-components/intersection
<template>
<div class="q-pa-md">
<div class="row justify-center q-gutter-sm">
<q-intersection
v-for="index in 60"
:key="index"
transition="scale"
class="example-item"
>
<q-card class="q-ma-sm">
<img src="https://cdn.quasar.dev/img/mountains.jpg">
<q-card-section>
<div class="text-h6">Card #{{ index }}</div>
<div class="text-subtitle2">by John Doe</div>
</q-card-section>
</q-card>
</q-intersection>
</div>
</div>
</template>
除了使用 QIntersection
有的元件本身也有Transition屬性
QImg
<template>
<div class="q-pa-md">
<q-btn
push
color="teal"
label="Trigger"
@click="trigger"
class="q-mb-md"
/>
<div class="q-gutter-md row items-start">
<!-- notice "basic" prop (which disables default animation) -->
<q-img
:src="url"
style="width: 150px"
:ratio="1"
basic
spinner-color="white"
class="rounded-borders"
>
<div class="absolute-bottom text-center text-italic text-body2">
None
</div>
</q-img>
<q-img
v-for="transition in transitions"
:key="transition"
:transition="transition"
:src="url"
style="width: 150px"
ratio="1"
spinner-color="white"
class="rounded-borders"
>
<div class="absolute-bottom text-center text-body2">
{{ transition }}
</div>
</q-img>
</div>
</div>
</template>
<script>
export default {
data () {
return {
url: 'https://placeimg.com/500/300/nature',
transitions: [
'slide-right',
'slide-left',
'slide-up',
'slide-down',
'fade',
'scale',
'rotate',
'flip-right',
'flip-left',
'flip-up',
'flip-down',
'jump-right',
'jump-left',
'jump-up',
'jump-down'
]
}
},
methods: {
trigger () {
this.url = 'https://placeimg.com/500/300/nature?t=' + Math.random()
}
}
}
</script>
QMenu
<template>
<div class="q-pa-md">
<div class="q-gutter-md row">
<q-btn color="primary" label="Flip Menu">
<q-menu
transition-show="flip-right"
transition-hide="flip-left"
>
<q-list style="min-width: 100px">
<q-item clickable>
<q-item-section>Having fun</q-item-section>
</q-item>
<q-item clickable>
<q-item-section>Crazy for transitions</q-item-section>
</q-item>
<q-separator />
<q-item clickable>
<q-item-section>Mind blown</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
<q-btn color="primary" label="Scale Menu">
<q-menu
transition-show="scale"
transition-hide="scale"
>
<q-list style="min-width: 100px">
<q-item clickable>
<q-item-section>Having fun</q-item-section>
</q-item>
<q-item clickable>
<q-item-section>Crazy for transitions</q-item-section>
</q-item>
<q-separator />
<q-item clickable>
<q-item-section>Mind blown</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
<q-btn color="primary" label="Jump Menu">
<q-menu
transition-show="jump-down"
transition-hide="jump-up"
>
<q-list style="min-width: 100px">
<q-item clickable>
<q-item-section>Having fun</q-item-section>
</q-item>
<q-item clickable>
<q-item-section>Crazy for transitions</q-item-section>
</q-item>
<q-separator />
<q-item clickable>
<q-item-section>Mind blown</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
<q-btn color="primary" label="Rotate Menu">
<q-menu
transition-show="rotate"
transition-hide="rotate"
>
<q-list style="min-width: 100px">
<q-item clickable>
<q-item-section>Having fun</q-item-section>
</q-item>
<q-item clickable>
<q-item-section>Crazy for transitions</q-item-section>
</q-item>
<q-separator />
<q-item clickable>
<q-item-section>Mind blown</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</div>
</div>
</template>
在quasar.config.js,設定要使用哪些Anmiate.css
可以配合vue的<transition>
Quasar can supply a big list of ready to use CSS animations. The animation effects are borrowed from Animate.css. So there are 80+ animation types available for you to use out of the box. Check the list either on Animate.css website or on the demo available for this page.
https://quasar.dev/options/animations#Usage
// embedding all animations
animations: 'all'
// or embedding only specific animations
animations: [
'bounceInLeft',
'bounceOutRight'
]
範例示意:
<template>
<q-page padding>
<transition
appear
enter-active-class="animated flash"
leave-active-class="animated flash"
>
<!-- Wrapping only one DOM element, defined by QBtn -->
<q-btn
color="secondary"
icon="mail"
label="Email"
/>
</transition>
</q-page>
</template>
<script>
export default {
name: 'DemoPage',
data () {
return {
}
},
mounted () {
}
}
</script>
載入與轉場雖然不是每個網頁的會遇到的需求
適當的使用,可以提升使用者的瀏覽體驗
載入比較常用於後端的需求
轉場動畫比較常出現在形象網站上
明天將以一個情境範例練習來結束第五個部分