import {
|
callPageHook
|
} from '../util'
|
|
function addKeepAliveInclude (componentName) {
|
if (this.keepAliveInclude.indexOf(componentName) === -1) { // 目标页面,自动 include
|
this.keepAliveInclude.push(componentName)
|
}
|
}
|
|
let deltaIds = []
|
|
function removeKeepAliveInclude (componentNameOrDelta) {
|
if (typeof componentNameOrDelta === 'number') {
|
deltaIds = this.keepAliveInclude.splice(-(componentNameOrDelta - 1)).map(name => {
|
return parseInt(name.split('-').pop())
|
})
|
} else {
|
const index = this.keepAliveInclude.indexOf(componentNameOrDelta)
|
if (index !== -1) {
|
this.keepAliveInclude.splice(index, 1)
|
}
|
}
|
}
|
|
let positionStore = Object.create(null)
|
|
export function getTabBarScrollPosition (id) {
|
return positionStore[id]
|
}
|
|
function saveTabBarScrollPosition (id) {
|
positionStore[id] = {
|
x: window.pageXOffset,
|
y: window.pageYOffset
|
}
|
}
|
|
function switchTab (routes, to, from) {
|
if (
|
to &&
|
from &&
|
to.meta.isTabBar &&
|
from.meta.isTabBar
|
) { // tabbar 跳 tabbar
|
saveTabBarScrollPosition(from.params.__id__)
|
}
|
// 关闭非 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(true)
|
for (let i = pages.length - 1; i >= 0; i--) {
|
callPageHook(pages[i], 'onUnload')
|
// 重新reLaunch至首页可能会被keepAlive,先手动强制destroy
|
pages[i].$destroy()
|
}
|
this.keepAliveInclude = []
|
// 清空 positionStore
|
positionStore = Object.create(null)
|
}
|
|
let currentPages = []
|
|
function beforeEach (to, from, next, routes) {
|
currentPages = getCurrentPages(true) // 每次 beforeEach 时获取当前currentPages,因为 afterEach 之后,获取不到上一个 page 了,导致无法调用 onUnload
|
const fromId = from.params.__id__
|
const toId = to.params.__id__
|
const toName = to.meta.name + '-' + toId
|
if (toId === fromId && to.type !== 'reLaunch') { // 相同页面阻止
|
// 处理外部修改 history 导致卡在当前页面的问题
|
if (to.fullPath !== from.fullPath) {
|
addKeepAliveInclude.call(this, toName)
|
next()
|
} else {
|
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
|
|
switch (to.type) {
|
case 'navigateTo':
|
break
|
case 'redirectTo':
|
// 关闭前一个页面
|
removeKeepAliveInclude.call(this, fromName)
|
if (from.meta) {
|
if (from.meta.isQuit) { // 如果 redirectTo 的前一个页面是 quit 类型,则新打开的页面也是 quit
|
to.meta.isQuit = true
|
to.meta.isEntry = !!from.meta.isEntry
|
}
|
// 小程序没有这个逻辑,当时为何加了保留并更新 tabBar 的逻辑?
|
// 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)
|
// }
|
}
|
|
break
|
case 'switchTab':
|
switchTab.call(this, routes, to, from)
|
break
|
case 'reLaunch':
|
reLaunch.call(this, toName)
|
to.meta.isQuit = true // reLaunch后,该页面为 quit 类型
|
break
|
default:
|
// 后退或非 API 访问
|
if (fromId && fromId > toId) { // back
|
removeKeepAliveInclude.call(this, fromName)
|
if (this.$router._$delta > 1) {
|
removeKeepAliveInclude.call(this, this.$router._$delta)
|
}
|
}
|
break
|
}
|
|
if (to.type !== 'reLaunch' && to.type !== 'redirectTo' && from.meta.id) { // 如果不是 reLaunch、redirectTo,且 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
|
const nvueDirKey = 'nvue-dir-' + __uniConfig.nvue['flex-direction']
|
if (to.meta.isNVue) {
|
document.body.setAttribute('nvue', '')
|
document.body.setAttribute(nvueDirKey, '')
|
} else {
|
document.body.removeAttribute('nvue')
|
document.body.removeAttribute(nvueDirKey)
|
}
|
}
|
}
|
|
next()
|
}
|
}
|
|
function afterEach (to, from) {
|
const fromId = from.params.__id__
|
const toId = to.params.__id__
|
let fromVm
|
// 使用 beforeEach 时的 pages
|
if (from.meta.isSet) {
|
fromVm = currentPages.find(pageVm => pageVm.$page.meta.pagePath === from.meta.pagePath)
|
} else {
|
fromVm = currentPages.find(pageVm => pageVm.$page.id === fromId)
|
}
|
|
function unloadPage (vm) {
|
if (vm) {
|
callPageHook(vm, 'onUnload')
|
const index = currentPages.indexOf(vm)
|
if (index >= 0) {
|
currentPages.splice(index, 1)
|
}
|
}
|
}
|
|
switch (to.type) {
|
case 'navigateTo': // 前一个页面触发 onHide
|
fromVm && callPageHook(fromVm, 'onHide')
|
break
|
case 'redirectTo': // 前一个页面触发 onUnload
|
unloadPage(fromVm)
|
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
|
unloadPage(fromVm)
|
if (this.$router._$delta > 1) {
|
deltaIds.reverse().forEach(deltaId => {
|
const pageVm = currentPages.find(pageVm => pageVm.$page.id === deltaId)
|
unloadPage(pageVm)
|
})
|
}
|
}
|
break
|
}
|
|
delete this.$router._$delta
|
deltaIds.length = 0
|
|
if (to.type !== 'reLaunch') { // 因为 reLaunch 会重置 id,故不触发 onShow,switchTab 在 beforeRouteEnter 中触发
|
// 直接获取所有 pages,getCurrentPages 正常情况下仅返回页面栈内,传 true 则返回所有已存在(主要是 tabBar 页面)
|
const pages = getCurrentPages(true)
|
let toVm
|
// 使用最新的 pages
|
if (to.meta.isSet) {
|
toVm = pages.find(pageVm => pageVm.$page.meta.pagePath === to.meta.pagePath)
|
} else {
|
toVm = pages.find(pageVm => pageVm.$page.id === toId)
|
}
|
if (toVm) { // 目标页面若已存在,则触发 onShow
|
// 延迟执行 onShow,防止与 UniServiceJSBridge.emit('onHidePopup') 冲突。
|
setTimeout(function () {
|
if (__PLATFORM__ === 'h5') {
|
UniServiceJSBridge.emit('onNavigationBarChange', toVm.$parent.$parent.navigationBar)
|
}
|
callPageHook(toVm, 'onShow')
|
}, 0)
|
if (__PLATFORM__ === 'h5') {
|
document.title = toVm.$parent.$parent.navigationBar.titleText
|
}
|
}
|
}
|
}
|
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)
|
})
|
}
|