Vue頁面跳轉動畫效果實現

前言

現如今移動端APP對用戶體驗方面的要求越來越高了,最近致力於用戶體驗優化,因爲需要實現類似APP頁面切換的動畫效果,百度google搜索資料不是很全,所以自己寫文檔,在實現效果的基礎上,順便惡補一波VueRouter及CSS過渡動畫的知識點,歡迎有興趣的朋友多多指教。

簡單demo圖預覽

 

 

 

寫在前面的思考

  • 如何匹配到相應需要跳轉的頁面?
  • 如何判斷是“前進”還是“後退”而後使用不同的動畫方式?
  • 如何對不同的跳轉設置動畫效果?

實現過程

一、vue路由匹配

創建vue實例,匹配路由。
用Vue.js + Vue Router創建單頁應用,是非常簡單的。使用Vue.js,我們可以通過組合組件來組成應用程序,將Vue Router 添加進來之後,我們需要做的是,將組件(components)映射到路由(routes),然後告訴Vue Router 在哪裏渲染它們。

import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
//如果使用模塊化機制編程,導入Vue和VueRouter,就需要調用Vue.use(Router)
複製代碼

接下來就可以進行路由組件的映射:
(路由)組件的定義可以自行定義,當然,爲了踐行模塊化組件化思想,多是從其他文件import進來。以下以簡單的“登錄->主頁->點單->結算”四個頁面的交互爲例:

import Login from '@/components/login' 
import Index from '@/components/index' 
import PointList from '@/components/pointList/pointList' 
import SettLement from '@/components/pointList/settlement' 

//創建router實例,然後傳入‘routes’配置
export default new Router({
  //routes配置可以直接傳入,也可以先定義後使用
  //每個路由都應該映射一個組件,其中component可以是通過Vue.extend()創建的組件構造器,
  或者只是一個組件配飾對象。(今天暫時不考慮嵌套路由的情況)
  routes: [
    {
      path: '/', // 登錄
      name: 'Login',
      component: Login
    },
    {
      path: '/index', // 主頁
      name: 'Index',
      component: Index
    },
    {
      path: '/pointList', // 點單
      name: 'PointList',
      component: PointList
    },
    {
      path: '/settLement', // 結算
      name: 'SettLement',
      component: SettLement
    }
]
})
複製代碼

二、路由跳轉 $router

組件路由除了使用全局組件 router-link 來實現點擊跳轉(相當於按鈕)外,還可以使用組件本身
具有的一個實例對象$router及其一些屬性來達到目標。  
$router 是VueRouter的一個實例對象,相當於一個全局的路由器對象。在Vue實例內部,你可以
通過$router訪問路由實例,裏面含有很多屬性和子對象,例如history對象,經常用到的跳轉鏈
接就可以調用this.$router.push,this.$router.push會往history棧中添加一個新記錄。
複製代碼
聲明式 編程式
<router-link :to="..." router.push(...)

點擊 等同於調用 router.push(...)
(...)該方法的參數可以是一個字符串,或者一個描述地址的對象:

// 字符串
router.push('home')
// 對象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})
// 帶查詢參數,變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
複製代碼

組件路由跳轉實例:
1.

<router-link :to="{name:'PointList', params: { userId: 123 }}">
      <i class="icon"><img src="../assets/point.png" alt=""></i>
      <span>點單</span>
</router-link>
複製代碼
  1.  
<footer class="version" @click="goPage('Author')">v 1.0</footer>
//Js:
methods: {
    goPage(url, param) {
      this.$router.push({ name: url });
    }
}
複製代碼

三、vue路由對象$route(只讀)

在使用了vue-router的應用中,路由對象會被注入每個組件中,賦值爲this.$route,並且當路由切換時,路由對象會被更新。所以route相當於當前正在跳轉的路由對象,可以從裏面獲取name,path,params,query等,即包含了當前URL解析得到的信息,還有URL匹配到的路由記錄。
路由對象暴露了以下屬性(常見):

  1. $route.path
字符串(string)。等於當前路由對象的路徑,會被解析爲絕對路徑,
如:http://example.com/#/login?name=aa,this.$route.path
,輸出“/login”,即對應上面1中路由匹配時routes配置中的“path”;
複製代碼
  1. $route.name
    字符串(string)。有時候,通過一個名稱來標識一個路由顯得更加方便,特別是在鏈接一個路由,或者是執行一些跳轉的時候。同樣,這裏的name也對應了routes配置中給某個路由設置名稱的name值:
    要鏈接到一個命名路由,可以給router-link的to屬性傳一個對象:
<router-link :to="{name:'Order', params: { userId: 123 }}">
</router-link>
複製代碼

用在調用router.push()中也是一回事:

this.$router.push({ name: 'Order', params: { userId: 123 }})
複製代碼
  1. $route.params
    對象(object)。路由跳轉攜帶參數:
this.$router.push({ name: 'Order', params: { userId: 123 }})
console.log(this.$route.params.userId); //123
複製代碼
  1. $route.query
    對象(object)。可訪問攜帶的查詢參數:
this.$router.push({name: 'login', query:{name: 'userName'}});
this.$route.query.name;    //you
//此時路由爲:"http://example.com/#/login?name=userName。"
複製代碼
  1. $route.redirectedFrom
    字符串(string)。重定向來源:
如:{ path: '*',redirect: {name: 'hello'}}
	此時訪問不存在的路由http://example.com/#/a會重定向到hello,
在hello訪問this.$route.redirectedFrom; 輸出“/a”。
複製代碼
  1. $route.matched
    數組(array)。當前路由下路由聲明的所有信息,從父路由(如果有)到當前路由爲止。
  2. $route.hash
    字符串(string)。當前路徑的hash值。

四、vue監聽$route的方式

watch:{‘$route’ (to, from) {}}
複製代碼

route 作爲vue實例的一個響應式屬性,和在data中寫的屬性本質上是一樣的,都可以通過this的方式拿到。既然你可以監聽data中的屬性變化,同樣也可以監聽route 的變化。watch中監聽的對象默認回調函數中的參數值就是newVal,oldVal。作爲 $route 屬性來說當然也就是 to 和 from 的概念了。
Vue用router.push(傳參)跳轉頁面,參數改變,在跳轉後的路由觀察路由變化,進行頁面刷新,可對“from->to”的過程設置動畫效果。
該功能的難點就在於怎樣獲取“上一頁”和“下一頁”,即怎樣分辨是“前進”還是“後退”?
例:

// watch $route 決定使用哪種過渡
watch:{
    '$route' (to, from) {
      //此時假設從index頁面跳轉到pointList頁面
      console.log(to); // "/pointList"
      console.log(from); // “/index”
      const routeDeep = ['/', '/index','/pointList', '/settLement'];
      const toDepth = routeDeep.indexOf(to.path)
      const fromDepth = routeDeep.indexOf(from.path)
      this.transitionName = toDepth > fromDepth ? 'fold-left' : 'fold-right'
    }
  },
複製代碼

to、from是最基本的路由對象,分別表示從(from)某個頁面跳轉到(to)另一個頁面,to.path(表示要跳轉到的路由地址),from.path同理。
定義routeDeep數組,將路由目錄按層級依次排序(暫不考慮嵌套路由的情況),複雜單頁應用裏,同一層級(如同一頁面上的多個導航按鈕)順序隨意,然後依次排列每個導航的下一頁、下下頁…即保證每個“上一頁”在“下一頁”前面。
總結下來就是:按照routeDeep數組裏定義的路由目錄的順序,“toDepth > fromDepth”表示“上一頁”跳轉到“下一頁”,同理可由此判斷是“前進”還是“後退”。

五、Vue2.0中transition組件的使用

<transition :name="transitionName">
    <router-view class="view app-view"></router-view>
</transition>
複製代碼
  • transition中有name屬性用於替換vue鉤子函數中的類名。
  • transition中只能有一個子元素並且該子元素需要有v-show或者v-if來控制是否顯示。

過渡CSS類名

transition中的name屬性用於 替換 vue鉤子函數中的類名transitionName-

  • transitionName-enter: 定義進入過渡的開始狀態。在元素被插入時生效,在下一個幀移除。
  • transitionName-enter-active: 定義進入過渡的結束狀態。在元素被插入時生效,在transition/animation完成之後移除。
  • transitionName-leave:定義離開過渡的開始狀態。在離開過渡被觸發時生效,在下一個幀移除。
  • transitionName-leave-active: 定義離開過渡的結束狀態。在離開過渡被觸發時生效,在transition/animation完成之後移除。
this.transitionName = toDepth > fromDepth ? 'fold-left' : 'fold-right'
複製代碼

在“watch $route”中,判斷頁面跳轉的“前進”和“後退”時,決定用不同的過渡效果(fold-left還是fold-right)。

六、animation、transform動畫效果實現

在上一個主題中,判斷頁面跳轉路徑之後,爲兩種跳轉的transition設置不同的類名“fold-left”、“fold-right”。
然後在CSS中,爲兩種類名設置不同的動畫效果(這裏以“左滑動”和“右滑動”爲例):

.fold-left-enter-active {
    animation-name: fold-left-in;
    animation-duration: .3s;
  }
  .fold-left-leave-active {
    animation-name: fold-left-out;
    animation-duration: .3s;
  }
.fold-right-enter-active {
    animation-name: fold-right-in;
    animation-duration: .3s;
  }
  .fold-right-leave-active {
    animation-name: fold-right-out;
    animation-duration: .3s;
  }
複製代碼

animation 屬性是一個簡寫屬性,用於設置六個動畫屬性:

描述
animation-name 規定需要綁定到選擇器的 keyframe 名稱。
animation-duration 規定完成動畫所花費的時間,以秒或毫秒計。
animation-timing-function 規定動畫的速度曲線。
animation-delay 規定在動畫開始之前的延遲。
animation-iteration-count 規定動畫應該播放的次數。
animation-direction 規定是否應該輪流反向播放動畫。
@keyframes fold-left-in {
    0% {
      transform: translate3d(100%, 0, 0);
    }
    100% {
      transform: translate3d(0, 0, 0);
    }
  }
  @keyframes fold-left-out {
    0% {
      transform: translate3d(0, 0, 0);
    }
    100% {
      transform: translate3d(-100%, 0, 0);
    }
  }
複製代碼

根據CSS3 @keyframes規則,創建動畫。創建動畫的原理即將一套CSS樣式逐漸變化爲另一套樣式。在動畫過程中,能夠多次改變這套CSS樣式。可以“百分比”來規定改變發生的時間,或者通過關鍵詞“from”和“to”,等價於“0%”(動畫的開始時間)和“100%”(動畫的結束時間)。一般爲了獲得最佳的瀏覽器支持,應該始終定義0%和100%選擇器。
transform屬性向元素應用2D或3D轉換。該屬性允許我們對元素進行旋轉、縮放、移動或傾斜。translate3d(x,y,z)定義3D轉換,如transform:translate3d(100%, 0, 0)只改變了x的值,即代表橫向左滑動,同理可相應推出其他情況。

七、寫在後面的坑 -- 頁面切換時空白閃屏的問題

優化前:

 

 

每次切換的時候,由於原頁面佔着主頁面的位置,其餘頁面,由於頁面div本身是block元素,所以其他block元素會另起一行,所以每次切換頁面時相當於從下面調出新頁面,所以會有一瞬的空白是從下面調出下一頁到主頁面的平行頁的過程,再執行動畫過渡命令。

 

解決:

給頁面CSS添加設置“position:absolute;”,此時頁面脫離文檔流,不佔空間,這樣就不會把下一頁擠下去,完成平滑過渡。 優化後:

 

 

 

暫時只用到了這個方法解決,可能也存在一定的弊端,如果有更好的方法,歡迎大家交流噢。

最後附上demo的代碼地址:vue頁面跳轉動畫效果demo

總結

以上就是vue頁面跳轉動畫效果功能實現的6個步驟,即這個功能中所含括的6個大知識點,當然其中還包括許多擴展的知識點,學無止境,需慢慢深入挖掘…


作者:mosa
鏈接:https://juejin.im/post/5ba358a56fb9a05d2068401d
來源:掘金
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章