在Web前端单页应用SPA(Single Page Application)中,路由描述的是URL与UI之间的映射关系,这种映射是单向的,即URL变化引起UI更新(无需以及不会刷新页面)
与window.location有关的api
http://www.joymood.cn:8080/test.php?user=admin&pwd=admin#login
location.href:得到整个如上的完整url
location.protocol:得到传输协议http:
location.host:得到主机名连同端口www.joymood.cn:8080
location.hostname:得到主机名www.joymood.cn
location.pathname:得到主机后部分不包括问号?后部分的/test.php
location.search:得到url中问号?之后井号#之前的部分?user=admin&pwd=admin
location.hash:得到#之前的部分#login
具体应用:
Vue等前端路由的实现
组件功能:
页面上监听浏览器前进后退操作,使得类似左侧点击列表,回退到上一个选中的列表,而非回退页面
弊端:
hash路由:https://music.163.com/#/playList?id=123456
因为只是改锚点#的内容,所以调用浏览器刷新时,不会丢失页面
history路由:https://music.163.com/playList?id=123456
因为改变的url是自定义的,并不是服务器上真实存在的路径,所以调用浏览器刷新时,页面会报404的错误
hash路由
hash是URL中hash(#)及后面的那部分,常用作锚点在页面内进行导航,改变URL中的hash部分不会引起页面刷新
通过hashchange事件监听URL的变化,改变URL的方式只有这几种:
(1)通过浏览器前进后退改变URL
(2)通过<a>标签改变URL
(3)通过window.location改变URL
(4)即使在hash模式下,依旧可以使用history.go,back,forward等触发hashchange事件,因为浏览器保存记录都是同一个栈
history路由
history提供了pushState和replaceState两个方法,这两个方法改变URL的path部分不会引起页面刷新
(1)history对象
history.state 存入浏览器记录中的值
history.back()
history.forward()
history.go(n) 去到指定记录,不填重新加载当前页
往浏览器中添加一条记录,在回退前进时会返回这些记录
history.pushState(放入浏览器的任意存储值,标题但浏览器都不支持null即可,'放在域名后的路径')
替换当前记录,类似重定向
history.replaceState(放入浏览器的任意存储值,标题但浏览器都不支持null即可,'放在域名后的路径')
(2)通过浏览器前进后退改变URL时会触发popstate事件
window.addEventListener('popstate',function(){
history.state 取得当前浏览器对象存储的值
})
不能监听的情况:
通过pushState/replaceState或<a>标签改变URL不会触发popstate事件
能监听的情况:
通过浏览器前进后退改变URL
history的back、go、forward方法
window.location
(3)对不能监听情况的处理
(1)拦截pushState/replaceState,即重写方法
var _wr = function(type) {
var orig = history[type];
return function() {
var e = new Event(type);
e.arguments = arguments;
window.dispatchEvent(e);
// 注意事件监听在url变更方法调用之前 也就是在事件监听的回调函数中获取的页面链接为跳转前的链接
var rv = orig.apply(this, arguments);
return rv;
};
};
history.pushState = _wr('pushState');
history.replaceState = _wr('replaceState');
window.addEventListener('pushState', function(e) {
var path = e && e.arguments.length > 2 && e.arguments[2];
var url = /^http/.test(path) ? path : (location.protocol + '//' + location.host + path);
console.log('old:'+location.href,'new:'+url);
});
window.addEventListener('replaceState', function(e) {
var path = e && e.arguments.length > 2 && e.arguments[2];
var url = /^http/.test(path) ? path : (location.protocol + '//' + location.host + path);
console.log('old:'+location.href,'new:'+url);
});
(2)劫持a标签的点击事件
event.preventDefault()
代码示例:
<div>
<button class="btn" onclick="btnFun();">点击新增一条历史记录</button>
</div>
<div>
<button class="btn" onclick="btnFun2();">点击新增一条历史记录2</button>
</div>
<!-- <script src='https://res.wx.qq.com/open/js/jweixin-1.3.2.js'></script> -->
<!-- <script src="./1.js"></script> -->
<script>
console.log('增加历史记录前 state的值:',history.state);
function btnFun() {
history.pushState('a',null,'index2.html?a=2');
console.log('增加历史记录后 state的值:',history.state);
// history.replaceState('b',null,'index3.html?b=2');
// console.log('增加历史记录后 state的值:',history.state);
};
function btnFun2() {
history.replaceState('c',null,'index4.html?c=2');
console.log('增加历史记录后 state的值:',history.state);
};
window.addEventListener('popstate',function() {
var state = history.state;
console.log(history)
console.log('点击后退按钮后 state的值:',state);
});
</script>