vue移動端路由切換完整實例

vue移動端路由切換完整實例

在寫移動端時,由於須要給頁面作轉場動畫,便有了此次的研究html

其中最主要的時如下兩個問題:vue

  1. 瀏覽器導航欄的切換
  2. IOS 上滑動切換時,會有兩次頁面的轉場動畫,一次自身滑動時進行的切換,隨後觸發咱們設置的轉場動畫。

除了上面兩個問題,其他的操做都是能夠在頁面內進行設置,基本都是可控的。主要就是解決上面兩個問題。ios

能夠看下實際寫出來的效果:在線DEMOgit

1. 瀏覽器導航欄的切換

經過記錄 歷史記錄 來比較判斷前進仍是後退github

  • 以下例子

A頁面 -> B頁面 -> C頁面數組

假如我從 A頁面到 B頁面 再到C頁面,歷史記錄就會產生3條瀏覽器

咱們用一個數組表示: ['/a', '/b', '/c']bash

而後我在經過點擊瀏覽器導航欄的後退按鈕, 我便會回到 B 頁面,markdown

這時候我只要判斷是否存在 B頁面, 存在就證實我點的時後退按鈕。dom

而後只要我後退過, 我就能點擊瀏覽器的前進按鈕了。這時候怎麼判斷它究竟是前進的呢。

咱們能夠這樣。

當咱們後退到了B頁面,歷史記錄不是還保存着['/a', '/b', '/c'] 三個路徑嗎

咱們能夠刪除B頁面後面的路徑,那如今就是 ['/a', '/b']; 若是咱們後退到A頁面, 那麼咱們保存的路徑就是['/a']

只要咱們點擊前進按鈕, 咱們去保存的路徑裏面找, 是否是就找不到路徑了, 那樣就完成了前進判斷。


上面是一種正常的狀況。 可是假如咱們有點頁面重複進入了呢。

  • 就如如下這種狀況

A頁面 -> B頁面 -> C頁面 -> B頁面 -> C頁面

如今走了5步,到達了第二個C頁面, 而後咱們後退一步,到達了B頁面 這個時候問題就出來了,咱們是刪除第一個B頁面後面的路徑仍是刪除第二個B頁面後面的路徑

  1. 咱們先試着刪除第二個B頁面的路徑,那麼咱們還保存的路徑就是: ['/a', '/b', '/c', '/b']。 那這個時候咱們按照上面正常狀況的邏輯來操做. 我點擊前進, 而後我去保存的路徑裏面找,找不到就算前進, 找到證實是後退。 那麼結果顯而易見,咱們找到了第一個C頁面,那就這樣就算後退了,但其實我點擊的時前進

  2. 那咱們試着刪除第一個B頁面後面的路徑,那麼保存的路徑就是: ['/a', '/b'], 那麼我在點擊後退按鈕,這時候他其實會進入C頁面, 咱們能夠看如下流程圖

    '圖片描述'
    這個時候咱們在此點擊後退按鈕,就會到C頁面, 可是保存的路徑裏面 '/c' 已經被我刪除了, 因此判斷出來的是前進。

  3. 若是咱們過濾重複的頁面路徑,是否是就會好了呢,其實也是同樣的 假如咱們有5個頁面路徑,過濾了2個重複的,只有3個頁面路徑了 那麼我退到第四個路徑的時候是否是就找不到了, 那麼後面兩個頁面都會算做前進。

因此以目前來看,最好的辦法就是記錄每個頁面,可是每一個頁面,都讓他有區別 那麼咱們就能夠在url上面放一個隨機字符串

代碼實現:

// 當沒有key的時候會進入兩次 beforeEach,咱們只需保存帶key的就行
const updateNavigations = (to) => {
    if (to.query[pathKey]) {
        store.commit('UPDATE_NAVIGATIONS', {path: to.fullPath})
    }
}

router.beforeEach((to, from, next) => {
    let toIndex = store.state.navigations.findIndex(path => path === to.fullPath)
    if (toIndex >= 0) { // 存在該路徑
        let len = store.state.navigations.length-1
        if (toIndex === len) { // 當前路徑是最後一條,證實是同一個頁面
            console.log('refresh') 
        } else { // 後退
            store.commit('UPDATE_ROUTER_DIRECTION', { routerDirection: 'back' }) // 後退標誌
            store.commit('DELETE_NAVIGATION', { index: toIndex }) // 刪除當前路徑後面的路徑
        }
    }else{ // 不存在該路徑
        store.commit('UPDATE_ROUTER_DIRECTION', { routerDirection: 'forward' }) // 前進標誌
        updateNavigations(to) // 保存該鏈接
    }

    const query = { ...to.query }
    // 存在就直接next, 防止死循環
    if (!query['APP_KEY']) { // 不存在添加key ,再次 next
        query['APP_KEY'] = Math.random().toString(16).substring(2)
        next({ path: to.path, query})
    }else{
        next()
    }
})
複製代碼

以上代碼咱們就能就url中添加一個 APP_KEY 的隨機串,那樣就算同一個頁面在咱們保存的路徑裏面也是實際上是不一樣的。就能夠正常的執行邏輯了 上面就基本解決了瀏覽器導航欄的問題了

2. IOS上的滑動切換

在IOS的網頁上, 是能夠左右滑動進行切換,即便你沒有作轉場動畫。 這個時候就會出現一個問題。

  • 仍是ABC頁面

A -> B -> C

當咱們到達C頁面,而後向左滑動時,滑完他就進入B頁面,可是這這時它仍是會進入咱們的 beforeEach 這個鉤子函數裏面,執行咱們上面的邏輯。 那樣就會觸發咱們的轉場動畫。你就會發現執行了兩次切換。

因而我在網上找到了一種方法 fix ios左滑再次執行動畫 #2259

代碼是這樣的

let touchEndTime = Date.now()

window.addEventListener('touchend', () => {
    touchEndTime = Date.now()
})

router.beforeEach((to, from, next) => {
    if ((Date.now() - touchEndTime) < 377) { // ios滑動切換
        store.commit('UPDATE_ROUTER_DIRECTION', { routerDirection: '' })
    }
})

複製代碼

上面也很好理解, 就是咱們取到手指最後離開的屏幕的那一刻, 而後在到 beforeEach裏面進行比較, 當手指離開屏幕的最後一刻跟咱們本身 beforeEach裏面進行的轉場相差小於 337, 就算是IOS的滑動切換

那樣就解決了IOS的滑動切換問題了。

可是IOS的右滑切換時監聽不到手指離開屏幕的那一刻的(也不知道是什麼鬼), 因此IOS的右滑切換,是無法像上面那樣判斷的。 這個我也沒找到解決辦法, 暫時只能解決IOS左滑返回的切換。

基本上遇到的比較麻煩的兩個點就是上面這兩個點了,其他都是能夠經過監聽事件進行設置,倒也沒什麼難度

在線DEMO演示

github: DEMO源碼

我的博客

相關文章
相關標籤/搜索