vue實現前進重新整理,後退不重新整理

SunnySky發表於2018-01-25

本文章存在缺陷,最後也沒能夠完善這個方案,大家看看就好。不過用這位大牛寫的專案可以解決問題,配置也特別簡單vue-navigaition

最近在用vue嘗試著做移動端的專案。希望實現前進重新整理、後退不重新整理的效果。即載入過的介面能快取起來(返回不用重新載入),關閉的介面能被銷燬掉(再進入時重新載入)。例如對a->b->c 前進(b,c)重新整理,c->b->a 後退(b,a)不重新整理。

由於keep-alive會把所有載入過的介面都快取起來,沒法實現返回時將介面銷燬掉,導致再進入時沒有重新載入這個介面。於是首先想到的方案是在點選介面上返回按鈕的時候,呼叫this.$destroy(true)來將介面銷燬掉。但是在移動端 android裝置上會有物理返回鍵,如果通過物理返回鍵返回的話,就沒法處理了。雖然可以重寫android的返回事件,來呼叫js的方法,但是呼叫的是js的全域性方法,沒法具體讓在最上層的那個介面銷燬掉。

於是就需要另闢蹊徑了。還好這篇文章給了我啟發vue-router 之 keep-alive,多謝作者的分享。

要是能夠知道路由是前進還是後退就好了,這樣的話我就能在後退的時候讓from路由的keepAlive置為falseto路由的keepAlive置為ture,就能在再次前進時,重新載入之前這個keepAlive被置為false的路由了。

廢話不多說了,這裡模擬有三個介面 loginservermain

首先我給這三個介面路由的path設定了嚴格的層級關係 ,並設定keepAlive都是true,預設都是需要快取。

const router = new Router({
  routes: [
    {
      path: '/',
      redirect: '/login'
    },
    {
      path: '/login',
      component: Login,
      meta: {
        keepAlive: true
      }
    },
    {
      path: '/login/server',
      component: ServerList,
      meta: {
        keepAlive: true
      }
    },
    {
      path: '/login/server/main',
      component: Main,
      meta: {
        keepAlive: true
      }
    }
  ]
})
複製程式碼

由於這三個介面path的層級不同,我就能通過beforeEach這個鉤子判斷出什麼時候是後退了。在後退時將from路由的keepAlive置為falseto路由的keepAlive置為ture

router.beforeEach((to, from, next) => {
  const toDepth = to.path.split('/').length
  const fromDepth = from.path.split('/').length
  if (toDepth < fromDepth) {
    console.log('後退。。。')
    from.meta.keepAlive = false
    to.meta.keepAlive = true
  }
  next()
})
複製程式碼

最後需要快取的介面用keep-alive包起來,就能實現時前進重新整理,後退時不重新整理的效果了。

        <keep-alive>
          <router-view v-if="$route.meta.keepAlive">
            <!-- 這裡是會被快取的檢視元件 -->
          </router-view>
        </keep-alive>

        <router-view v-if="!$route.meta.keepAlive">
          <!-- 這裡是不被快取的檢視元件 -->
        </router-view>
複製程式碼

補充說明

這個方法確實很取巧,像lyh2668所說的單純從length判斷會有很多場景有問題。比如 有一個page5介面,我需要能從page3page4介面都能跳轉過去的話,那就需要為page5配置兩個路由path了,假設page幾的path層級就是幾的話,那麼就要為page5配置層級4和層級5的兩個路由路徑了(當然直接就配置一個路由層級5的話也是可行的,只需要保證比跳轉到它的介面的層級都大就可以)。

另外可以像lyh2668所說的把keepAlive換成noKeepAlive,這樣的話就不用在每個router中去配置keepAlive了,就方便了很多。關於層級也可以不通過/來判斷,比如在path末尾加數字等其它方式來實現。

另外lyh2668所說的壓棧的方式,我也有搜到過,但是在有tab介面的時候這種方式就不適合了,因為tab介面切換的時候不需要這種效果,但也會被壓棧。但是用我的方法的話,就可以把tab介面的路由都設定為同一個層級,就不會有問題了

這是是壓棧方式的程式碼,在沒有tab介面的時候,這種方式確實會更好用。

let routerList = []
router.beforeEach((to, from, next) => {
    if (routerList.length && routerList.indexOf(to.name) === routerList.length - 1) {
      // 後退
      routerList.splice(routerList.length - 1, 1)
      to.meta.isBack = true
    } else {
      // 前進
      routerList.push(from.name || '/')
      to.meta.isBack = false
    }
    next()
})
複製程式碼

歡迎有更好方法的朋友能夠指點分享。

已新增Demo說明,見github。包括普通介面切換、tab介面切換和不同層級介面的切換示例。

相關文章