基於vue-router的移動端網頁的路由管理


本篇代碼示例:github

前提:不關注移動端瀏覽器的前進事件

涵蓋功能:
 1,管理路由的歷史記錄

 2,切頁動畫的實現

 3,處理流程類頁面的回退事件

描述:

   流程類頁面的回退事件的解釋:
 以注冊頁面舉例, 為了拉長整個流程,把輸入項分開。以下是整個流程(懶得畫圖,大家將就看)

 1.首頁 - 點擊首頁注冊按鈕可進入注冊輸入頁

 2.注冊輸入頁 - 輸入姓名

 3.注冊輸入頁 - 輸入電話

 4.提交注冊頁 - 點擊提交按鈕,獲取注冊狀態(成功或者失敗),如果成功,則跳轉到指定頁面(假定是產品頁)

 5.產品頁

 以上是一個簡單的注冊的流程,現在寫一下業務場景和需求

 1,注冊未完成時 

   注冊未完成時,頁面可能處於 1,2,3,4 這幾個頁面,此時,點擊返回(無論是頁面本身自帶的返回,還是瀏覽器或者設備-[如安卓]的返回鍵觸發的返回) 均可回到上一頁

 2.注冊完成時

  指注冊成功並已經進入 5 頁面 ,此時,點擊返回(瀏覽器或者設備-[如安卓]的返回鍵觸發的返回),回到 4 頁面之后,要求直接跳回 1 頁面

 

准備工作

 1.切頁動畫的實現

  切頁動畫使用vue自帶的 過渡效果 transition 實現, 這個是附帶的,這里不講,大家自己看代碼,代碼如下

<template>
  <div class="wapper">
    <transition :name="transition">
      <router-view class="child-view"></router-view>
    </transition>
  </div>
</template>

<script>

export default {
  name: 'tableDemo',
  data () {
    return {
      transition: 'slide-left'
    }
  },
  methods: {
    doSomething (e) {
      this.$router.delLastRouter() // 頁面回退時,路由做對應的處理
    }
  },
  created () {
    window.addEventListener('popstate', this.doSomething, false) // 監聽回退事件
  },
  beforeRouteUpdate (to, from, next) {
    window.document.title = to.meta.title
    let isBack = this.$router.isBack
    if (isBack) {
      this.transition = 'slide-right'
      next()
    } else {
      // 進入頁面之前判斷是否是進入流程頁
      if (from.meta.isStartPage) {
        this.$router.setProcessStatus(to.meta.group, false)
      }
      this.transition = 'slide-left'
      next()
    }
  }
}
</script>

<style lang="scss">
.wapper { position: relative; width: 100%; height: 100%;}
.child-view { position: absolute; width:100%; height: 100%;}
.slide-left-leave { -webkit-transform: translate(0, 0); transform: translate(0, 0);}
.slide-left-leave-active { transition: all .4s cubic-bezier(.55,0,.1,1);}
.slide-left-leave-to { -webkit-transform: translate(100%, 0); transform: translate(100%, 0);}
.slide-left-enter { -webkit-transform: translate(-100%, 0); transform: translate(-100%, 0);}
.slide-left-enter-active { transition: all .4s cubic-bezier(.55,0,.1,1);}
.slide-left-enter-to { -webkit-transform: translate(0, 0); transform: translate(0, 0);}

.slide-right-leave { -webkit-transform: translate(0, 0); transform: translate(0, 0);}
.slide-right-leave-active { transition: all .4s cubic-bezier(.55,0,.1,1);}
.slide-right-leave-to { -webkit-transform: translate(-100%, 0); transform: translate(-100%, 0);}
.slide-right-enter { -webkit-transform: translate(100%, 0); transform: translate(100%, 0);}
.slide-right-enter-active { transition: all .4s cubic-bezier(.55,0,.1,1);}
.slide-right-enter-to { -webkit-transform: translate(0, 0); transform: translate(0, 0);}

</style>

 

 2.路由的管理

  1. 為vue-router設置一些狀態

Router.prototype.routerArray = []; // 存儲過往的路由信息
Router.prototype.processArray = []; // 存儲流程頁的狀態
Router.prototype.isBack = false; // 是否是返回,動畫使用

  2. 使用 beforeRouteUpdate 來檢查路由的變化 這里要注意的事情是 beforeRouteUpdate 只針對子路由生效  ,所以這段代碼放在父路由指向的頁面中

  在這個頁面,我們通過 this.$router.isBack 來區分頁面是前進還是后退,並調整對應的動畫效果。

beforeRouteUpdate (to, from, next) {
    window.document.title = to.meta.title
    let isBack = this.$router.isBack
    if (isBack) {
      this.transition = 'slide-right'
      next()
    } else {
      // 進入頁面之前判斷是否是進入流程頁
      if (from.meta.isStartPage) {
        this.$router.setProcessStatus(to.meta.group, false)
      }
      this.transition = 'slide-left'
      next()
    }
  }

  3. 重寫路由的push方法  在push方法中 如果push指向的頁面已經存在於歷史記錄中,則當做返回處理, 前進則為 歷史記錄添加一條數據

// 修改 Router本身的push, 跳轉之前做一些判斷
    let lPush = Router.prototype.push;
    Router.prototype.push = function (location, onComplete, onAbort) {
      let lGoCount = this.havRouterHistory(location)
      if (lGoCount < 0) {
        this.isBack = true
        this.go(lGoCount);
      } else {
        this.isBack = false
        this.routerArray.push(this.history.current)
        lPush.call(this, location, onComplete, onAbort)
      }
    };

  4.重寫路由的go方法 

// 重寫 Router 本身的 go, 回退的同時要清空記錄中的數據
    let lGo = Router.prototype.go
    Router.prototype.go = function (n) {
      if (n > 0) {
        lGo.call(this, n);
        return;
      }
      let lLen = 0 - n;
      lLen = this.routerArray.length > lLen ? lLen : this.routerArray.length;
      let lStart = this.routerArray.length - lLen;
      this.routerArray.splice(lStart, lLen);
      lGo.call(this, n);
    };

  5.判斷 push 時 指向的頁面是否存在於歷史記錄中

// 判斷歷史記錄中是否存在將要跳轉的路由,如果有,執行回退操作
    Router.prototype.havRouterHistory = function (location) {
      // debugger
      let lPath = location.path;
      let lName = location.name;
      let lLen = this.routerArray.length;
      for (let i = 0; i < lLen; i++) {
        if (this.routerArray[i].path === lPath || this.routerArray[i].name === lName ) {
          return i - lLen; // 存在則返回應該回退的步數,注意回退的步數是負值
        }
      }
      return 1 // 如果存在則必然小於0,所以這里寫返回1代表不存在沒有問題
    };

  6.瀏覽器或者設備物理鍵觸發回退

  在父路由頁面設置全局的事件監聽,在觸發事件的時候處理路由

methods: {
    doSomething (e) {
      this.$router.delLastRouter() // 頁面回退時,路由做對應的處理
    }
  },
  created () {
    window.addEventListener('popstate', this.doSomething, false) // 監聽回退事件
  },
// 瀏覽器回退時,清除最后一條路由數據  這串代碼在 路由配置文件 中
    Router.prototype.delLastRouter = function () {
      this.routerArray.pop()
    }

  7. 路由本身的回退事件   無需對路由的back事件做處理,因為vue-router本身的back 調用的  go(-1) go函數我們已經重寫過了

  8.根據流程相關頁面,對路由做相對應的配置

  isStartPage: true // 表示這是一個流程入口頁,相當於上面的 頁面1

  group  // group分組,代表了一組頁面同屬於一個流程中

/**
 * 返回效果的Demo
 */
export default [
  {
    path: '/backDemoIndex',
    name: 'backDemoIndex',
    component: r => require.ensure([], () => r(require('../../Page/BackDemo/index')), 'BackDemo/index'),
    meta: { title: '入口選擇頁面' }
  },
  {
    path: '/backAPage',
    name: 'backAPage',
    component: r => require.ensure([], () => r(require('../../Page/BackDemo/aPage')), 'BackDemo/aPage'),
    meta: { title: '操作起始頁面aaaaa', isStartPage: true }
  },
  {
    path: '/backAPageA',
    name: 'backAPageA',
    component: r => require.ensure([], () => r(require('../../Page/BackDemo/aPagea')), 'BackDemo/aPagea'),
    meta: { title: '操作起始頁面bbb', isStartPage: true }
  },
  {
    path: '/backAPageB',
    name: 'backAPageB',
    component: r => require.ensure([], () => r(require('../../Page/BackDemo/aPageb')), 'BackDemo/aPageb'),
    meta: { title: '操作起始頁面CCC', isStartPage: true }
  },
  {
    path: '/backBPage',
    name: 'backBPage',
    component: r => require.ensure([], () => r(require('../../Page/BackDemo/bPage')), 'BackDemo/bPage'),
    meta: { title: '第一個輸入頁面', group: 'backDemo' }
  },
  {
    path: '/backCPage',
    name: 'backCPage',
    component: r => require.ensure([], () => r(require('../../Page/BackDemo/cPage')), 'BackDemo/cPage'),
    meta: { title: '第二個輸入頁面', group: 'backDemo' }
  },
  {
    path: '/backDPage',
    name: 'backDPage',
    component: r => require.ensure([], () => r(require('../../Page/BackDemo/dPage')), 'BackDemo/dPage'),
    meta: { title: '結果頁面', group: 'backDemo' }
  },
  {
    path: '/other',
    name: 'other',
    component: r => require.ensure([], () => r(require('../../Page/BackDemo/other')), 'BackDemo/other'),
    meta: { title: '結果頁面' }
  }
]

  9.在流程起始頁進入流程頁是,修改流程的狀態

  this.$router.setProcessStatus( ‘backDemo’, false)  //  groupName 流程分組名稱   status  流程狀態 true為已經完成  false 為 未完成

// 修改一個流程的狀態
    Router.prototype.setProcessStatus = function (groupName, status) {
      this.processArray[groupName] = status
    };

  10.在每個流程頁 檢查流程的完成情況

  this.$router.onPageLoad()

// 找到最近的入口頁面
    Router.prototype.findInsterPage = function () {
      let lLen = this.routerArray.length;
      for (let i = lLen - 1; i >= 0; i--) {
        if (this.routerArray[i].meta.isStartPage) {
          return i - lLen
        }
      }
      return 1; // 如果存在則必然小於0,所以這里寫返回1代表不存在沒有問題
    }

    // 如果進入一個流程頁,並且該頁面的狀態已經是完成,則應該回退到最近的流程入口頁面,或者 跳轉到指定的頁面
    Router.prototype.onPageLoad = function (query) {
      // debugger
      if (this.history.current.meta.group) {
        let lNowRouter = this.history.current.meta.group
        let lStatus = this.processArray[lNowRouter]
        if (lStatus) {
          let lRes = this.findInsterPage()
          if (lRes < 0) {
            this.go(lRes)
          }
        }
      }
    };
    

  11. 在流程結果處理頁面,更改流程狀態為完成  this.$router.setProcessStatus( ‘backDemo’, true)

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM