iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

0
Modern Web

30天Vue出Google SSO系列 第 29

Day 29. F2E-完善過渡動畫

https://ithelp.ithome.com.tw/upload/images/20201015/201186862xQ8U8yXmv.jpg

昨天後來在看效果時,有發現過渡動畫的元素已經完全超出卡片組件的範圍了,這個不是我們想要的效果
理想中的效果是要在卡片組件中完成,不能超出範圍


#加上進度條

這裡提供兩種方式解決超出範圍的問題

#第一種

可以在卡片組件的CSS屬性加上 overflow: hidden,將超出組件的部分隱藏:
加上後就可以達到不超過卡片組件的過渡動畫效果!!

<v-card style="overflow: hidden;">
  ...
</v-card>

#第二種

雖然第一種很簡單就能解決,但我們不用它xD
我們用第二種解法,在卡片組件中加上 loading,參考Vuetify v-card API:

<v-card :loading="card.loading">
  ...
</v-card>
  • loading(true/false): 卡片組件的進度條顯示

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 保持雙向溝通

#Step 1

loading 傳入子分頁:

<router-view
  :loading.sync="card.loading"
></router-view>

#Step 2

子分頁接收 loading:

//KeyinUser.vue
export default {
  name: "KeyinUser",
  props: ["loading"],
}

KeyinUser.vue 為例,其他子分頁如 KeyinPswd.vueChooseUser.vueVerifyUser.vue 都是相同的設定

#Step 3

再來很重要的一步,監聽 loading
如果loading值存在而且是 true 則設定1秒後改為 false,時間可以自行調整但操作上要保持良好流暢度

//KeyinUser.vue
watch: {
  loading: {
    handler(newValue, oldValue) {
      if (newValue) {
        setTimeout(() => {
          this.$emit("update:loading", false);
        }, 1000);
      }
    },
    immediate: true,
  },
},

#結果

到這邊就完成進度條的控制囉!!
來看看畫面~
gif已死QQ

應該有發現雖然過渡動畫元素沒有超過卡片組件,而且也有進度條的效果了,但是整體非常不和協,連LOGO標題都跟著位移了,還有錄影錄不出來的部分,整個卡片組件內容在切換頁面時會跳針...

這個問題我花了一天半查原因...
最後終於發現原來是卡片組件的 autofocus 屬性惹的禍/images/emoticon/emoticon36.gif
把這個屬性移除就正常了,推測是因為過渡元素還沒顯示出來就聚焦導致畫面偏移,但會發生衝突的原因我沒有深入探討,有興趣的人可以研究看看xD

來看看目前的畫面~
gif已死QQ


#autofocus替代方案

卡片組件的 autofocus 拿掉解決了衝突的問題,但我們還是需要這個效果怎麼辦?

還記得在表單驗證時我們用了 $refs 抓到表單元件後呼叫手動驗證的方法嗎?

在這裡,可以利用它再次幫我們抓到文字輸入框,並呼叫聚焦(focus)的方法

#Step 1

文字輸入框加上屬性 ref 並給它一個命名:

//KeyinUser.vue
<v-text-field
  ref="eleAccountId"
  ...
></v-text-field>

KeyinUser.vue 為例,同理可套在 KeyinPswd.vue

#Step 2

聚焦方法的觸發時機可以寫在監聽 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)方法

#結果

來看看目前的畫面~
看起來順暢多了!!
gif已死QQ


#加上遮罩

先來看一段我跟過渡動畫拚手速的畫面xD
gif已死QQ

有發現嗎? 我的手速可媲美加藤...(咳咳)
手速不是重點,有發現過渡動畫還沒結束就被我截斷了嗎? 這是蠻不好的使用者體驗

好的使用者體驗是讓過渡動畫完整呈現後,才能繼續下一步操作

而為了避免發生有人跟我一樣手速超快的問題,這裡使用了 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>
  • absolute(true/false): 組件加上 position: absolute 屬性
  • opacity(0~1): 遮罩層透明度,從0到1為完全透明到完全不透明
  • value(true/false): 遮罩層是否顯示
    因為觸發時機和過渡動畫相同,所以也用 loading 值做開關
  • color: 遮罩層顏色

對應的data:

data() {
  return {
    card: {
      ...,
      overlay: {
        absolute: true,
        opacity: 0.3,
        color: "#FFF",
      },
    },
  };
},

#結果

加上遮罩層之後,就算加藤鷹之手也沒辦法破解它xD
gif已死QQ


今日重點:

  • 卡片組件加上進度條(loading)效果,同時實現過渡動畫元素不超出範圍,loading 由子分頁監聽並控制關閉
  • 卡片組件 autofocus 造成跳針問題使用手動聚焦(focus)方法來代替,由 loading 值控制觸發時機
  • Vuetify 組件的API查詢及使用

到這邊整體專案就100%完成囉!!

有需要改進或是任何意見建議歡迎下面留言~


上一篇
Day 28. F2E-過渡動畫
下一篇
Day 30. 結語
系列文
30天Vue出Google SSO30

尚未有邦友留言

立即登入留言