文章目录
在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路由
hash是URL中hash(#)及后面的那部分,常用作锚点在页面内进行导航,监听 window 的 hashchange 事件,当散列值改变时,可以通过 location.hash 来获取和设置hash值
//设置 url 的 hash,会在当前url后加上'#abc'
window.location.hash='abc';
let hash = window.location.hash //'#abc'
window.addEventListener('hashchange',function(){
//监听hash变化,点击浏览器的前进后退会触发
})
-
通过hashchange事件监听URL的变化
- 能监听的情况
- 通过浏览器前进后退改变URL
- 浏览器输入URL中hash变化
- 通过<a>标签改变URL
- <a>标签的属性 href 可以设置为页面的元素ID如 #top,当点击该链接时页面跳转至该id元素所在区域,同时浏览器自动设置 window.location.hash 属性,地址栏中的哈希值也会发生改变,并触发onhashchange事件
- 通过window.location改变URL
- 即使在hash模式下,依旧可以使用history.go,back,forward等触发hashchange事件,因为浏览器保存记录都是同一个栈
-
优点
- 改变URL中的hash部分不会引起页面刷新,散列值是不会随请求发送到服务器端的,所以改变hash,不会重新加载页面
-
弊端
- SEO不行
history路由
history提供了pushState和replaceState两个方法,这两个方法改变URL的path部分不会引起页面刷新
history.state 存入浏览器记录中堆顶的值
history.length 当前窗口访问过的网址数量(包括当前网页)
history.back()
history.forward()
history.go(n) 去到指定记录,不填或0刷新当前页
往浏览器中添加一条记录,在回退前进时会返回这些记录
history.pushState(放入浏览器的任意存储值,标题但浏览器都不支持''即可,'放在域名后的路径')
替换当前记录,类似重定向
history.replaceState(放入浏览器的任意存储值,标题但浏览器都不支持''即可,'放在域名后的路径')
// 每当 history 对象出现变化时,就会触发 popstate 事件。
window.addEventListener('popstate',function(event){
history.state||event.state 取得当前浏览器对象存储的值
})
-
不能监听的情况:
- 通过pushState/replaceState或<a>标签改变URL不会触发popstate事件
- 该事件只针对同一个文档,如果浏览历史的切换,导致加载不同的文档,该事件也不会触发。
- 页面第一次加载的时候,浏览器不会触发popstate事件
-
能监听的情况:
- 通过浏览器前进后退改变URL
- history的back、go、forward方法
- window.location
-
对不能监听情况的处理
- 劫持a标签的点击事件:event.preventDefault()
- 拦截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;
};
};
// 重写自定义方法,内部通过window.dispatchEvent(e)调用自定义监听
history.pushState = _wr('pushState');
history.replaceState = _wr('replaceState');
// 自定义监听pushState、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);
});
-
弊端
- history路由:https://music.163.com/playList?id=123456
因为改变的url是自定义的,并不是服务器上真实存在的路径,所以调用浏览器刷新时,页面会报404的错误
- history路由:https://music.163.com/playList?id=123456
代码示例:
<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>