1. 路由
- 传统的路由指的是:当用户访问一个
时,对应的服务器会接收这个请求,然后解析url中的路径,从而执行对应的处理逻辑。这样就完成了一次路由分发。url
- 而前端路由是不涉及服务器的,是前端利用
或者hash
的HTML5
来实现的,一般用于不同内容的展示和切换。history API
目前
Vue
推荐单页面应用
SPA
开发模式,大型单页应用最显著特点之一就是采用前端路由系统,通过改变
URL
,在不重新请求页面的情况下,更新页面视图。
Vue
中的路由解决方案为
vue-router
。
它提供两种不同方式的路由方式:
Hash
和
History
,在
vue-router
中是使用了外观模式将几种不同的路由方式提供了一个一致的高层接口,让我们可以更解耦的在不同路由方式中切换。
Hash
和
History
除了外观上的不同之外,还有一个区别是:
Hash
方式的状态保存需要另行传递,而
HTML5 History
原生提供了自定义状态传递的能力,我们可以直接利用其来传递信息。
在
vue-router
中是通过
mode
这一参数控制路由的实现模式的:
2. Hash
Hash
方法是在路由中带有一个
#
,主要原理是通过监听
#
后的
URL
路径标识符的更改而触发的浏览器
hashchange
事件,然后通过获取
location.hash
得到当前的路径标识符,再进行一些路由跳转的操作,参见 MDN:
-
:返回完整的location.href
;URL
-
:返回location.hash
的锚部分;URL
-
:返回location.pathname
路径名;URL
-
事件:当hashchange
发生改变时,将触发这个事件。location.hash
比如访问一个路径
http://sherlocked93.club/base/#/page1
,那么上面几个值分别为:
# http://sherlocked93.club/base/#/page1
{
"href": "http://sherlocked93.club/base/#/page1",
"pathname": "/base/",
"hash": "#/page1"
}
看一个例子:
<html>
<head>
<style>
li {
cursor: pointer;
}
</style>
</head>
<body>
<div id="main">
<p>router-hash</p>
<ul id="list">
<li><a href="#router1" target="_blank" rel="external nofollow" >router1</a></li>
<li><a href="#router2" target="_blank" rel="external nofollow" >router2</a></li>
<li><a href="#router3" target="_blank" rel="external nofollow" >router3</a></li>
</ul>
<div id="panel"></div>
</div>
<script>
window.onload = function () {
window.onhashchange = function (opt) {
console.log('hash has changed to: ', location.hash)
}
}
</script>
</body>
</html>
效果:
当我们点击后退时,可见路由跳转回
router2
中。并且当我们刷新页面时不会报出
404
的错误,那是因为
hash
虽然出现在
URL
中,但不会被包括在
HTTP
请求中。它是用来指导浏览器动作的,对服务器端完全无用。
3. History API
HTML5
的
History API
为浏览器的全局
history
对象增加的扩展方法。一般用来解决
ajax
请求无法通过回退按钮回到请求前状态的问题。
在
HTML4
原有的和
HTML5
新提出的
history
的API有:
-
; //在历史记录中前进一步history.forward()
-
; //在历史记录中后退一步history.back()
-
: //在历史记录中跳转n步骤,n=0为刷新本页,n=-1为后退一页。history.go(n)
-
//向历史记录中追加一条记录history.pushState(data, title, url);
-
//替换当前页在历史记录中的信息history.replaceState(data, title, url);
-
//是一个属性,可以得到当前页的history.state;
信息。state
-
//是一个事件,在点击浏览器后退按钮或window.onpopstate;
调用js
、forward()
、back()
时触发。监听函数中可传入一个go()
对象,event
即为通过event.state
或pushState()
方法传入的replaceState()
参数。data
以一个例子实现一下:
<html>
<head>
<style>
li {
cursor: pointer;
}
</style>
</head>
<body>
<div id="main">
<p>vue-router</p>
<ul id="list">
<li>router1</li>
<li>router2</li>
<li>router3</li>
</ul>
<div id="panel"></div>
</div>
<script>
window.onload = function () {
window.onpopstate = function (event) {
console.log(event)
};
document.querySelector('#list').addEventListener('click', function (event) {
if(event.target.nodeName.toLowerCase()==="li") {
var content = event.target.innerHTML;
var _newState;
_newState = {
url: location.origin + '/' + content,
title: document.title,
state: content
};
window.history.pushState(_newState, '', '/' + content);
console.log('you have change the router to: ', content);
}
})
}
</script>
</body>
</html>
效果:
总而言之就是当浏览器访问一个页面时,当前地址的状态信息会被压入历史栈,当调用
history.pushState()
方法向历史栈中压入一个新的
state
后,历史栈顶部的指针是指向新的
state
的。可以将其作用简单理解为假装已经修改了
url
地址并进行了跳转 ,除非用户点击了浏览器的前进、回退,或是显式调用
HTML4
中的操作历史栈的方法,否则不会触发全局的
popstate
事件。以上例子中点击后退可见由当前的
router2
跳转到
router3
,控制台打印出
popstate
事件信息。
当我们刷新页面的时候,会报出
404
的错误:
这也是
history
不同于
hash
的一个地方,是因为
history
模式则会将
URL
修改得就和正常向后端发起请求一样,如果后端没有配置对应的路由处理,则会返回
404
错误。
官方推荐的解决办法是在服务端增加一个覆盖所有情况的候选资源:如果
URL
匹配不到任何静态资源,则应该返回同一个
index.html
页面,这个页面就是你
app
依赖的页面。
参考:
https://www.cnblogs.com/dashnowords/p/9671213.html 大史不说话
https://juejin.im/post/5c52da9ee51d45221f242804 SHERlocked93