iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 29
1
Modern Web

Quasar CLI Framework 邪教:整合分散的前端技術和工具、常見的開發需求系列 第 29

第二十九天:UI切版 & 元件-視覺效果(載入中、轉場、動畫)

今天的內容

一、載入中
二、轉場
三、動畫
四、總結

一、載入中

當我們在處理非同步的需求,中間會有一個等待時間
在等待的過程中,我們可以在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

  • transition

<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

  • transition-show="flip-right"
  • transition-hide="flip-left"

<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>

四、總結

載入與轉場雖然不是每個網頁的會遇到的需求
適當的使用,可以提升使用者的瀏覽體驗

載入比較常用於後端的需求
轉場動畫比較常出現在形象網站上
明天將以一個情境範例練習來結束第五個部分


上一篇
第二十八天:UI切版 & 元件-清單表格、彈出視窗
下一篇
第三十天:UI切版 & 元件-第五部分情境練習(註冊表單、產品清單、登入頁面)
系列文
Quasar CLI Framework 邪教:整合分散的前端技術和工具、常見的開發需求31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言