vue-router 頁面切換動畫

vue-router 頁面切換動畫

網上一直沒翻到 vue-router 翻頁動畫的完美實現,就心[bei]動[bi]的,編了一個簡單的動畫組件。支持簡單的前進後退的左右動畫,針對不支持 history.state 的瀏覽器,也能支持簡單的透明動畫。

獻上效果圖:

預覽

可下載此項目,打開 test.html,點擊瀏覽器的前進、後退按鈕,觀看具體效果。項目地址

使用

使用前,請確保項目內,已經使用了 vue-loader

在需要動畫的頁面中,引用 src/vue-page-animation.vue 文件,並且在 router-view 組件中,添加 class="vue-page-animation-router-view",具體如下:

<template>
  <div class="app">
    <VuePageAnimation>
      <keep-alive>
        <router-view class="vue-page-animation-router-view"></router-view>
      </keep-alive>
    </VuePageAnimation>
  </div>
</template>

<script>
import VuePageAnimation from '../src/vue-page-animation';
export default {
  components: {
    VuePageAnimation
  },
}
</script>

動畫鉤子

  • 左右切換鉤子: vue-page-animation-left, vue-page-animation-right
  • 透明動畫鉤子: vue-page-animation-fade 針對不支持 history api 瀏覽器的簡單透明動畫
  • 如要強制指定某種動畫,可給組件配置 force-transition-name 屬性,用於指定動畫的鉤子

對於低性能的機子,強烈建議,都指定 force-transition-name="vue-page-animation-fade",避免左右切換動畫,導致頁面渲染出現殘影、fixed元素錯位等問題。

滾動距離修正

若不想自動修正滾動距離,可以給進入頁面的根元素,配置 data-vue-paga-animation-backdata-vue-paga-animation-forward 屬性,用於指定頁面前進、後退 進入時,頁面的初始化滾動位置,如:

<!-- pageA.vue -->
<template>
  <div class="page-a" data-vue-paga-animation-back="20" data-vue-paga-animation-forward="20">
    內容..
  </div>
</template>

頁面在 進入或後退 進入時,默認滾動 20px 距離

關於 scrollBehavior

scrollBehavior,它是 vue-router 中,記錄滾動位置的方法,用法如下:

const router = new Router({
  routes: [
    // 一堆路由配置
  ],
  scrollBehavior (to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return { x: 0, y: 0 }
    }
  }
});

配上動畫,效果如下:

對比圖

雖能記錄滾動位置,但在執行動畫前,會導致頁面跳動。最後無奈放棄

實現原理

判斷前進和後退:
1. 使用 history api 保存頁面信息,如果不支持此 api,則放棄判斷,使用 fade 動畫
2. history.state.rid 頁面的唯一 id,此 id 的值是請求的時間,所以通過 id 大小的判斷,就可以知道是前進還是後退了
3. 記錄滾動位置的 map 對象,使用 history.state.rid 作爲 key 值,如果不支持 history api,則使用 url 作爲 key 值

修復滾動軸位置:
1. 在動畫前,鎖定body層的滾動軸
2. 如何鎖定滾動軸?給 body 設置 position: fixed; width: 100%; overflow-y: scroll;
3. 然後,給當前離開的頁面,修正 top 的位置
4. 同時,獲取正在進入的頁面的滾動距離,並修正 top 的位置
5. 待動畫結束後,刪除 body 的樣式,同時,刪除正在進入、離開元素的 top 屬性,同時修正滾動軸的位置

如何獲取頁面切換前,滾動軸的位置?
1. 方法一: 監聽 window.onscroll,定時記錄滾動軸的位置
2. 方法二: router.beforeEach 方法,在動畫前,記錄下滾動軸的位置

不能在 popstate 時記錄,因爲 vue-router 是可能走 hash 形式的。

最終,此組件選擇了方式二的變種,router 對象中,有一個 beforeHooks 屬性,此屬性記錄了所有 router.beforeEach 添加的函數鉤子。

組件裏,通過this.$router.beforeHooks.push()的形式,加入新的函數鉤子。同時,在組件銷燬、不可見時,通過this.$router.beforeHooks.splice()方式,移除函數鉤子。

入坑須知

  1. 因用到 position:fixed,所以組件的動畫,是 top 和 opacity 切換,性能上會有些許影響。如確保不會使用到 position:fixed,請果斷使用 transform 動畫。
  2. 修正 top 時,偶爾會有 1px 的抖動,有大神來指點一下嗎?
  3. 如果某天 vue-routerbeforeHooks 幹掉了,就只能與 router.beforeEach 玩耍了
  4. 此項目木有測試同學參與,木有測試同學參與,木有測試同學參與
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章