router-guard.js 5.6 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
import {
  callPageHook
} from '../util'

function addKeepAliveInclude (componentName) {
  if (this.keepAliveInclude.indexOf(componentName) === -1) { // 目标页面,自动 include
    this.keepAliveInclude.push(componentName)
  }
}

function removeKeepAliveInclude (componentName) {
  const index = this.keepAliveInclude.indexOf(componentName)
  if (index !== -1) {
    this.keepAliveInclude.splice(index, 1)
  }
}

function switchTab (routes) {
  // 关闭非 tabBar 页面
  const pages = getCurrentPages()
  for (let i = pages.length - 1; i >= 0; i--) {
    const pageVm = pages[i]
    const meta = pageVm.$page.meta
    if (!meta.isTabBar) {
      removeKeepAliveInclude.call(this, meta.name + '-' + pageVm.$page.id)
      callPageHook(pageVm, 'onUnload')
    }
  }
}

function reLaunch (toName) {
  __uniConfig.reLaunch = (__uniConfig.reLaunch || 1) + 1
  // 关闭所有页面
  const pages = getCurrentPages()
  for (let i = pages.length - 1; i >= 0; i--) {
36 37 38
    callPageHook(pages[i], 'onUnload')
    // 重新reLaunch至首页可能会被keepAlive,先手动强制destroy
    pages[i].$destroy()
fxy060608's avatar
fxy060608 已提交
39 40 41 42
  }
  this.keepAliveInclude = []
}

43 44
let currentPages = []

fxy060608's avatar
fxy060608 已提交
45
function beforeEach (to, from, next, routes) {
46
  currentPages = getCurrentPages(true) // 每次 beforeEach 时获取当前currentPages,因为 afterEach 之后,获取不到上一个 page 了,导致无法调用 onUnload
fxy060608's avatar
fxy060608 已提交
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
  const fromId = from.params.__id__
  const toId = to.params.__id__
  if (toId === fromId) { // 相同页面阻止
    next(false)
  } else if (to.meta.id && to.meta.id !== toId) { // id 不妥,replace跳转
    next({
      path: to.path,
      replace: true
    })
  } else {
    const fromName = from.meta.name + '-' + fromId
    const toName = to.meta.name + '-' + toId

    switch (to.type) {
      case 'navigateTo':
        break
      case 'redirectTo':
        // 关闭前一个页面
        removeKeepAliveInclude.call(this, fromName)
66 67 68 69 70 71 72 73 74 75 76 77 78
        if (from.meta) {
          if (from.meta.isQuit) { // 如果 redirectTo 的前一个页面是 quit 类型,则新打开的页面也是 quit
            to.meta.isQuit = true
            to.meta.isEntry = !!from.meta.isEntry
          }
          if (from.meta.isTabBar) { // 如果是 tabBar,需要更新系统组件 tabBar 内的 list 数据
            to.meta.isTabBar = true
            to.meta.tabBarIndex = from.meta.tabBarIndex
            const appVm = getApp().$children[0]
            appVm.$set(appVm.tabBar.list[to.meta.tabBarIndex], 'pagePath', to.meta.pagePath)
          }
        }

fxy060608's avatar
fxy060608 已提交
79 80 81 82 83 84
        break
      case 'switchTab':
        switchTab.call(this, routes)
        break
      case 'reLaunch':
        reLaunch.call(this, toName)
85
        to.meta.isQuit = true // reLaunch后,该页面为 quit 类型
fxy060608's avatar
fxy060608 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
        break
      default:
        // 后退或非 API 访问
        if (fromId && fromId > toId) { // back
          removeKeepAliveInclude.call(this, fromName)
        }
        break
    }

    if (to.type !== 'reLaunch' && from.meta.id) { // 如果不是 reLaunch,且 meta 指定了 id
      addKeepAliveInclude.call(this, fromName)
    }
    // if (to.type !== 'reLaunch') { // TODO 如果 reLaunch,1.keepAlive的话,无法触发页面生命周期,并刷新页面,2.不 keepAlive 的话,页面状态无法再次保留,且 routeView 的 cache 有问题
    addKeepAliveInclude.call(this, toName)
    // }
    if (process.env.NODE_ENV !== 'production') {
      console.debug(`Core:keepAliveInclude=${JSON.stringify(this.keepAliveInclude)}`)
    }
    /* eslint-disable no-undef */
    if (__PLATFORM__ === 'h5') {
      if (to.meta && to.meta.name) {
        document.body.className = 'uni-body ' + to.meta.name
      }
    }

    next()
  }
}

function afterEach (to, from) {
  const fromId = from.params.__id__
  const toId = to.params.__id__

119
  const fromVm = currentPages.find(pageVm => pageVm.$page.id === fromId) // 使用 beforeEach 时的 pages
fxy060608's avatar
fxy060608 已提交
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142

  switch (to.type) {
    case 'navigateTo': // 前一个页面触发 onHide
      fromVm && callPageHook(fromVm, 'onHide')
      break
    case 'redirectTo': // 前一个页面触发 onUnload
      fromVm && callPageHook(fromVm, 'onUnload')
      break
    case 'switchTab':
      if (from.meta.isTabBar) { // 前一个页面是 tabBar 触发 onHide,非 tabBar 页面在 beforeEach 中已触发 onUnload
        fromVm && callPageHook(fromVm, 'onHide')
      }
      break
    case 'reLaunch':
      break
    default:
      if (fromId && fromId > toId) { // history back
        fromVm && callPageHook(fromVm, 'onUnload')
      }
      break
  }
  if (to.type !== 'reLaunch') { // 因为 reLaunch 会重置 id,故不触发 onShow,switchTab 在 beforeRouteEnter 中触发
    // 直接获取所有 pages,getCurrentPages 正常情况下仅返回页面栈内,传 true 则返回所有已存在(主要是 tabBar 页面)
143
    const toVm = getCurrentPages(true).find(pageVm => pageVm.$page.id === toId) // 使用最新的 pages
fxy060608's avatar
fxy060608 已提交
144
    if (toVm) { // 目标页面若已存在,则触发 onShow
X
xiaoyucoding 已提交
145
      // 延迟执行 onShow,防止与 UniServiceJSBridge.emit('onHidePopup') 冲突。
146
      setTimeout(function () {
X
xiaoyucoding 已提交
147 148
        callPageHook(toVm, 'onShow')
      }, 0)
fxy060608's avatar
fxy060608 已提交
149 150 151 152 153 154 155 156 157 158 159 160 161
    }
  }
}
export default function initRouterGuard (appVm, routes) {
  // 处理keepAliveInclude
  appVm.$router.beforeEach(function (to, from, next) {
    beforeEach.call(appVm, to, from, next, routes)
  })
  // 处理前进时的 onUnload,onHide 和后退时的 onShow
  appVm.$router.afterEach(function (to, from) {
    afterEach.call(appVm, to, from)
  })
}