第二十九天: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>

四、总结

载入与转场虽然不是每个网页的会遇到的需求
适当的使用,可以提升使用者的浏览体验

载入比较常用於後端的需求
转场动画比较常出现在形象网站上
明天将以一个情境范例练习来结束第五个部分


<<:  [Day29]拖稿到最後的逆向工程

>>:  Get Pogo Support If Pogo Games Not Working Call 1888-614-3222

【Day 08】工厂方法设计模式(Python)

前言 上一篇我们讨论DDD的战术设计,它建议引用各种设计模式,提高生产力,因此接下来,就来介绍各种设...

[Day 25] 中场休息 - 没信用卡的学生福星,heroku

好的,由於昨天aws架设完环境後今天突然爆炸了 所以可能要重新架过aws 那今天就先来讲讲没有信用卡...

Day 16 - Rancher 指令工具的操作

本文将於赛後同步刊登於笔者部落格 有兴趣学习更多 Kubernetes/DevOps/Linux 相...

【Mac用户必看】6款超实用的Mac软件推荐

虽然Mac上已经有很多好用的内置程序,但我们还是经常听到这样的问题:在我启动 Macbook/iMa...

范围和裁缝(Scoping and Tailoring)

**范围界定(Scoping)**是指检查基准安全控制并仅选择适用於您要保护的IT系统的那些控制。例...