iportal
Version:
web-portal
123 lines (111 loc) • 3.43 kB
text/typescript
'use strict'
import { Application } from '../Application'
import { TransformProptey } from './proptey'
import { PopState } from '../types'
class TransformHistory extends TransformProptey {
public history: number = 0
public historyIndex: number = history.length
public historyDirection: number = 0
private backoutCount: number = 0
private silentObserver: number | undefined = undefined
constructor (app: Application) {
super(app)
this.bindHistoryState()
}
private bindHistoryState () {
addEventListener('load', () => {
addEventListener('popstate', (event: PopStateEvent) => {
this.popstate(event.state)
clearInterval(this.silentObserver)
}, false)
}, false)
}
private obserSilent () {
this.silentObserver = setInterval(() => {
if (history.state?.id !== this.id) {
this.popstate(history.state)
}
}, 100) as unknown as number
}
public popstate (state: PopState) {
const { historyIndex = 0 } = state ?? {}
if (historyIndex === this.historyIndex) {
this.historyDirection = 0
} else if (historyIndex > this.historyIndex) {
this.historyDirection = 1
} else {
this.historyDirection = -1
}
this.historyIndex = historyIndex
this.back(state)
}
public pushState (id = '', title = '', search = location.search, param = '') {
id = encodeURIComponent(id)
const length = history.length
history.pushState({
id,
title,
time: Date.now(),
search,
historyIndex: length
}, title, location.pathname + search + '#' + id + '/' + param)
this.historyIndex = length + 1
this.historyDirection = 1
if (this.silentObserver === undefined) {
this.obserSilent()
}
}
public replaceState (id = '', title = '', search = location.search, param = '') {
id = encodeURIComponent(id)
const length = history.length
history.replaceState({
id,
title,
time: Date.now(),
search,
historyIndex: length
}, title, location.pathname + search + '#' + id + '/' + param)
this.historyIndex = length
this.historyDirection = 1
}
public async back (state?: PopState) {
const options = this.options
const route = state || history.state || this.app.route
const id = decodeURIComponent(route.id) || options.index || 'frameworks'
const search = route.search
const module = await this.app.get(id)
if (!module) return
/**
* 如果设置了单向锁,且回退时模块层级为 0 时
* 阻止返回,并发送事件
*/
if (this.checkSingleLock()) {
this.backoutCount++
if (this.options.holdBack?.(this.backoutCount) === true) {
this.pushState(id, module.config.title, search)
this.app.trigger('exit', {
backoutCount: this.backoutCount
})
}
return
} else {
this.backoutCount = 0
}
const inLevel = module.config.level ?? 0
const outLever = this.module.config.level ?? 0
if (options.singleFlow && module.config.level !== 0 && inLevel >= outLever) {
return history.back()
}
this.app.transform.to(id, search, -1)
this.app.trigger('back', {
id,
module
})
}
public checkSingleLock (): boolean {
return this.options.singleLock && this.module.config.level === 0 && this.historyDirection === -1 ? true : false
}
}
export {
TransformHistory
}