HTML5History
class HTML5History extends History{
_startLocation;
constructor(router,base){
super(router,base)
// Get the initial HTML5 route
this._startLocation = getLocation(this.base)
}
setupListeners(){
if(this.listeners.lenth > 0) {return
}
// Current routing instance
const router = this.router
// The rolling behavior of route switching
const expectScroll = router.options.scrollBehavior
// Check whether historyPushState is supported and whether the scroll behavior exists
const supportsScroll = supportsPushState && expectScroll
if(supportScroll){
// Record the current scroll position
this.listeners.push(setupScroll())
}
const handleRoutingEvent = () = > {
const current = this.current
const location = getLocation(this.base)
// The current route is in the initial state
if(this.current === START && location === this._startLocation){
return
}
// Redirect route
this.transitionTo(location,route= > {
// Scroll after jump
if(supportScroll){
handleScroll(router,route,current,true)}}}window.addEventListener('popstate',handleRoutingEVent)
this.listeners.push(() = > {
window.removeEventListener('popstate',handleRoutingEvent)
})
}
// Perform the jump
go(n){
window.history.go(n)
}
push(location,onComplete,onAbort){
const { current: fromRoute } = this
// Perform the jump
this.transitionTo(location,route= > {
// Update the browsing history
pushState(cleanPath(this.base+ route.fullPath))
// Perform the scroll
handleScroll(this.router,route,fromRoute,false)
onComplete && onComplete(route)
},onAbort)
}
replace(location,onComplete,onAbort){
const { current: fromRoute } = this
// Perform the jump
this.transitionTo(location,route= > {
// Replace the browsing history
replaceState(cleanPath(this.base + route.fullPath))
// Perform the scroll
handleScroll(this.router,route,fromRoute,false)
onComplete && onComplete(route)
},onAbort)
}
ensureURL(push){
// Check whether there is no jump to the current path
if(getLocation(this.base) ! = =this.current.fullPath){
const current = cleanPath(this.base+ this.current.fullPath)
push ? pushState(current) : replaceState(current)
}
}
// Get the current path
getCurrentLocation(){
return getLocation(this.base)
}
}
Copy the code
setupScroll
function setupScroll(){
// Use browser features to return to the scroll position of the previous page. Auto scroll manual does not scroll
if('scrollRestoration' in window.history){
window.history.scrollRestoration = 'manual'
}
// Get the domain name
const protocolAndPath = window.location.protocol + '/ /' + window.location.host
// Get the absolute path
const absolutePath = window.location.href.replace(protocolAndPath,' ')
// Copy the browser record
const stateCopy = extend({},window.history.state)
stateCopy.key = getStateKey()
// Replace the browser record with the current link
window.history.replaceState(stateCopy,' ',absolutePath)
// Listen page changes trigger record scroll position
window.addEvenetListener('popstate',handlePopState)
return () = > {
window.removeEventListener('popstate',handlePopState)
}
}
Copy the code
getStateKey
const Time = inBrowser && window.performance && window.performance.now ? window.performance : Date
const genStateKey = () = > Time.now().toFixed(3) // Get the current time
let _key = genStateKey()
const getStateKey = () = > _key // Get the current time as key
const setStateKey = (key) = > _key = key
Copy the code
handlePopState
function handlePopState(e){
// Record the location
saveScrollPosition()
// Record the page time
if(e.state && e.state.key){
setStateKey(e.state.key)
}
}
const positionStore = Object.create(null)
function saveScrollPosition(){
// Record the scroll position of the current point in time
const key = getStateKey()
if(key){
positionStore[key] = {x:window.pageXOffset,y:window.pageYOffset}
}
}
Copy the code
handleScroll
function handleScroll(router,to,from,isProp){
// No vue instance is mounted
if(! router.app){return
}
// Determine that there is no scrolling behavior
const behavior = router.options.scrollBehavior
if(! behavior){return}...// The scrolling behavior must be a function
router.app.$nextTick(() = > {
// Get the current scroll position
const position = getScrollPosition()
// Returns the position to which you should scroll
const shouldScroll = behavior.call(router,to,from,isProp ? position : null)
if(! shouldScroll)return
// Perform the scroll
if(typeof shouldScroll.then === 'function'){
shouldScroll.then(shouldScroll= > {
scrollPosition(shouldScroll,position)
}).catch(err= > {
if(process.env.NODE_ENV ! = ='production'){
assert(false,err.toString)
}
})
}else{
scrollPosition(shouldScroll,position)
}
})
}
Copy the code
scrollPosition
function scrollPosition(shouldScroll,position){
const isObject = typeof shouldScroll === 'object'
// Get the location
if(isObject && typeof shouldScroll.selector === 'string') {/ / get the dom
const el = hashStartsWithNumberRE.test(shouldScroll.selector) ? document.getElementById(shouldScroll.selector.slice(1)) : document.querySelector(shouldScroll.selector)
if(el){
let offset = shouldScroll.offset && typeof shouldScroll.offset === 'object' ? shouldScroll.offset : {}
offset = normalizeOffset(offset)
position = getElementPosition(el,offset)
}else if(isValidPosition(shouldScroll)){
position = normalizePosition(shouldScroll)
}
}else if(isObject && isValidPosition(shouldScroll)){
position = normalizePosition(shouldScroll)
}
// Perform the scroll behavior
if(position){
if('scrollBehavior' in document.documentElement.style){
window.scrollTo({
left: position.x,
top: position.y,
behavior: shouldScroll.behavior
})
}else{
window.scrollTo(position.x,position.y)
}
}
}
Copy the code
getLocation
function getLocation(base){
let path = window.location.pathname
// Get a path other than base
if(base && path.toLowerCase().indexOf(base.toLowerCase()) === 0){
path = path.slice(base.length)
}
// Returns the current location
return (path || '/') + window.location.search + window.location.hash
}
Copy the code
supportPushState
// Check whether the system version supports pushState
const supportPushStat = inBrowser && (function(){
const ua = window.navigator.userAgent
if( (ua.indexOf('Android 2.')! = = -1 || ua.indexOf('the Android 4.0')! = = -1)&& ua.indexOf('Mobile Safari')! = = -1 && ua.indexOf('chrome') = = = -1 && ua.indexOf('WindowsPhone') = = =)return false
return window.history && typeof window.history.pushState === 'function'}) ()Copy the code
pushState
function pushState(url,replace){
// Store the current scroll position
saveScrollPosition()
const history = window.history
// Perform the jump
try{
if(replace){
const stateCopy = extend({},history.state)
stateCopy.key = getStateKey()
// Replace the browsing record and change the record time
histroy.replaceState(stateCopy,' ',url)
}else{
// Update the browsing history
history.pushState({key:setStateKey(getStateKey())},' ',url)
}
}catch(e){
window.location[replace ? 'replace' : 'assign'](url)
}
}
Copy the code