这篇文章主假如记录下HTML5中history供应的pushState
, replaceState
API。末了经由过程这些API本身完成小型的路由。
关于window.history供应的API请拜见Mozilla文档
个中history
供应的pushState
和replaceState
2个API供应了操纵阅读器汗青栈的要领。
个中pushState
:
history.pushState(data, null, '#/page=1');
pushState吸收3个参数,第一个参数为一个obj,示意阅读器
第二个参数是document.title的值,平常设定为`null`
第三个参数string,用以转变 当前url
pushState
要领在转变url
的同时向阅读器汗青栈中压入新的汗青记录。
吸收url
的参数为string
范例,用以转变当前地点栏的url.须要注重的一点就是这个参数不能和跨域,即协定,域名,端口必需都是雷同的,假如涌现跨域的状况,即会提醒:
Uncaught DOMException: Failed to execute 'pushState' on 'History': A history state object with URL 'http://www.baidu.com/' cannot be created in a document with origin 'http://commanderXL.com' and URL
Example:
翻开www.baidu.com
history.pushState(null, null, '?page=1')
//地点栏变成 www.baidu.com/?page=1
history.pushState(null, null, '#page=2');
//地点栏变成 www.baidu.com/#page=2
个中replaceState
:
history.replaceState(null, null, '#page=2');
replaceState
吸收的参数pushState
雷同,然则终究的结果是:地点栏url会依据吸收的参数而变化,然则阅读器并未在当阅读汗青栈中增添阅读器的汗青记录,而是替代当前的阅读器汗青记录。
经由过程pushState
和replaceState
虽然能转变URL,然则不会主动触发阅读器reload
。
window
对象还供应popstate
要领:
window.addEventListener('popstate', function() {
});
这个要领用以监听阅读器在差别汗青记录中举行切换,而触发响应的事宜。
在阅读器供应的history对象上另有go
, back
要领,用以模仿用户点击阅读器的行进退却按钮。在某个web运用当中,比方点击了<a>
标签,发作了页面的跳转。这时候挪用history.back()
;要领后页面回退,同时页面发作革新,这时候window.onpopstate
没法监听这个事宜。然则假如是经由过程pushState
或许replaceState
来转变URL且不发作阅读器革新的话,再运用history.back()
或history.go()
,如许popstate
事宜会被触发。
history.pushState({page: 1}, null, '?page=1');
history.pushState({page: 2}, null, '?page=2');
history.back(); //阅读器退却
window.addEventListener('popstate', function(e) {
//在popstate事宜触发后,事宜对象event保留了当前阅读器汗青记录的状况.
//e.state保留了pushState增加的state的援用
console.log(e.state); //输出 {page: 1}
});
PS: 经由过程pushState
在url上增加?page=1
能够经由过程location.search
去猎取search
的内容。不过假如经由过程location.search
去转变url
的话是会主动触发阅读器reload
的。这个特征能够和下面将的关于hash
的内容对比下。
API大抵了解了,那末这些要领能够运用到哪些地方呢?一个比较经常使用的场景是就在单页运用中,经由过程这些API完成前端的路由设想,应用pushState
, replaceState
能够转变url
同时阅读器不革新,而且经由过程popstate
监听阅读器汗青记录的体式格局,完成一系列的异步行动。
<a data-href="/post"></a>
<a data-href="/login"></a>
//路由
const Router = [];
const addRoute = (path = '', handle = () => {}) => {
let obj = {
path,
handle
}
Router.push(obj);
}
//增加路由定义
addRoute('/post', function() {
//do something
});
addRoute('/login', function() {
//do something
})
//路由处置惩罚
const routeHandle = (path) => {
Router.forEach((item, index) => {
if(item.path === path) {
item.handle.apply(null, [path]);
return true;
}
})
return false;
}
//阻拦默许的a标签行动
document.addEventListener('click', function(e) {
let dataset = e.target.dataset;
if(dataset) {
if(routeHandle(dataset.href)) {
//阻挠默许行动
e.preventDefault();
}
}
})
大抵的完成思绪就是,经由过程<a>
增加路由信息,然后阻拦<a>
标签的默许行动,并与注册的路由信息举行婚配。若婚配胜利挪用对应的handle
要领.
不过pushState
和replaceState
要领在低版本的IE阅读器下兼容性不是很好。所以能够举行降级运用hash
来举行路由设想。
hash
?请戳我。
能够经由过程location.hash
猎取url
上第一个#(fragment)
及背面的内容。同时还能经由过程location.hash
改写其内容,且不会主动触发阅读器reload
。 有些功用是否是和pushState
和replaceState
一样? 所以为了兼容到低版本的阅读器,能够经由过程监听#
变化来举行路由设想。
那末怎样去监听呢? 比较粗犷的一种体式格局就是polling
。
var oldHash = location.hash;
setTimeInterval(function() {
if(oldHash !== location.hash) {
//do something
oldHash = location.hash;
}
}, 100);
不过,H5还供应了一个API: hashchange
。它的就能够直接替代上面的polling
要领,来监听#
的变化。
window.addEventListener('hashchange', function() {
routeHandle(locaiton.hash);
});
这个小型的路由设想能够拜见我的github.
轻微总结下:
上面重要引见了history供应的一些API,hash的相干学问。在日常平凡能够运用到SPA当中,Gmail就是经由过程hash来举行路由设想的。它相对于页面跳转来讲:
页面只须要加载一次。背面的页面切换能够经由过程ajax去要求数据。页面体验越发流通;
能够应用当地缓存,优化页面体验。在差别页面切换的过程当中越发流通;
可举行按需加载…
等等一些有用的优点吧。