/* @flow */
//用于判断是否是浏览器环境
import { inBrowser } from './dom'
//保存滚动的位置(x,y).
import { saveScrollPosition } from './scroll'
// genStateKey 生成基于当前时间时间戳的key。
// setStateKey 更新key。
// getStateKey 获取key。
import { genStateKey, setStateKey, getStateKey } from './state-key'
// extend(a, b) 将 b 对象中属性浅拷贝到 a 对象中。
import { extend } from './misc'
/*
判断浏览器是否支持 history 模式。
*/
export const supportsPushState =
//inBrowser 是否是浏览器环境。
inBrowser &&
(function () {
//获取用户代理对象。
const ua = window.navigator.userAgent
//满足下面条件的 ua,则不支持 html5 的导航模式。
if (
(ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
ua.indexOf('Mobile Safari') !== -1 &&
ua.indexOf('Chrome') === -1 &&
ua.indexOf('Windows Phone') === -1
) {
return false
}
//判断window 是否存在 history对象,且 pushState 方法是否存在。
//如果都存在,则表明支持 html5 的导航模式。
return window.history && typeof window.history.pushState === 'function'
})()
/*
push 方式跳转新路径,会在 history 中记录。
*/
export function pushState(url?: string, replace?: boolean) {
//保存当前页面滚动的位置。
saveScrollPosition()
// try...catch the pushState call to get around Safari
// DOM Exception 18 where it limits to 100 pushState calls
//获取导航对象
const history = window.history
try {
if (replace) {
//保存之前 history 的 state。
// preserve existing history state as it could be overriden by the user
const stateCopy = extend({}, history.state)
stateCopy.key = getStateKey()
//使用 history 的 replace 方法。
// 第一个参数是 state. 这里就是 { key: “当前时间的时间戳字符串” }
// 第二个参数是 title, 这个值没有意义了。
// 第三个参数是 url, 要跳转的url。
history.replaceState(stateCopy, '', url)
} else {
//使用 history 的 push 方法。
// 第一个参数是 state
// 第二个参数是 title
// 第三个参数是 url
history.pushState({ key: setStateKey(genStateKey()) }, '', url)
}
} catch (e) {
//如果抛出了异常,则表示栈已经到了最大值,不能push了。
//使用 location.assign 也可以用来跳转网址,且 assign 会添加记录到浏览历史,点击后退可以返回到之前页面。
window.location[replace ? 'replace' : 'assign'](url)
}
}
/*
replace 方式跳转新路径,不会在 history 中记录。
*/
export function replaceState(url?: string) {
//第二个参数是 true,表示以 replace 的方式去跳转到新页面。
pushState(url, true)
}