一、什么是路由?
路由是根据不同的url地址来显示不同的页面或内容。
当我们访问一个url地址的时候,大致流程可以想象成这样:
- 浏览器向服务器发出请求;
- 服务器监听到80端口,如果有请求,那么就解析url地址。
- 服务器根据路由配置,然后就返回相应的信息(比如html字符串、json数据或图片等)。
- 浏览器根据服务器响应的Content-Type来决定如何解析数据。
以上就是传统路由最初始的实现方式,缺点是每次路由切换都需要刷新页面,发ajax请求,然后把数据返回回来,这样对用户体验就不好了。
因此为了提升用户体验,前端路由就产生了,它就可以解决浏览器不会重新刷新了。
在了解路由之前,先简单的看一下history api有哪些方法:
> window.history.length: 返回当前会话浏览的页面数量;
> window.history.go(): 接收一个整数作为参数,按照当前页面在会话浏览历史记录中的位置进行移动;
> window.history.back(): 移动到上一页。相当于点击浏览器的后退按钮;
> window.history.forward(): 移动到下一页,相当于点击浏览器的前进按钮;
> window.history.pushState(): 在会话浏览历史记录中添加一条记录;
> window.history.replaceState(): 该方法用法和history.pushState方法类似,但是该方法的含义是将修改会话浏览历史的当前记录,而不是新增一条记录。
有了这些基本知识后,我们再来看下前端路由,前端路由也有2种模式,第一种是hash模式,第二种是history模式。我们来分别看下这两种知识点及区别如下:
二、hash模式
hash路由模式是这样的:http://xxx.com/#/xx。 带#号,后面就是hash值的变化。实现hash路由的基本条件:
- url中hash值的改变,并不会重新加载页面;
- hash值的改变会在浏览器的访问历史中增加一条记录,可以通过浏览器的后退,前进按钮控制hash值的切换;
- 可以通过hashchange事件,监听到hash值的变化,从而加载不同的页面显示。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>hash test</title>
</head>
<body>
<p>hash test</p>
<button id="btn">修改 hash</button>
<script>
// hash 变化,包括:
// a. JS 修改 url
// b. 手动修改 url 的 hash
// c. 浏览器前进、后退
window.onhashchange = (event) => {
console.log('old url', event.oldURL)
console.log('new url', event.newURL)
console.log('hash:', location.hash)
}
// 页面初次加载,获取 hash
// 当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发
document.addEventListener('DOMContentLoaded', () => {
console.log('hash:', location.hash)
})
// JS 修改 url
document.getElementById('btn').addEventListener('click', () => {
location.href = '#/user'
})
</script>
</body>
</html>
三、history模式
- 用url规范的路由,但跳转时不刷新页面;
- window.history.pushState 能修改路径、查询参数和片段标识符。pushState比hash更符合前端路由的访问方式,更加优雅(因为不带#号);
- window.onpopstate来监听历史栈的改变,只要历史栈有信息发生改变的话,就会触发该事件。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>history API test</title>
</head>
<body>
<p>history API test</p>
<button id="btn">修改 url</button>
<script>
// 页面初次加载,获取 path
document.addEventListener('DOMContentLoaded', () => {
console.log('load', location.pathname)
})
// 打开一个新的路由
// 【注意】用 pushState 方式,浏览器不会刷新页面
document.getElementById('btn').addEventListener('click', () => {
const state = { name: 'page1' }
console.log('切换路由到', 'page1')
history.pushState(state, '', 'page1') // 重要!!!
})
// 监听浏览器前进、后退
window.onpopstate = (event) => { // 重要!!!
console.log('onpopstate', event.state, location.pathname)
}
</script>
</body>
</html>
需要 server 端配合,可参考
https://router.vuejs.org/zh/guide/essentials/history-mode.html#%E5%90%8E%E7%AB%AF%E9%85%8D%E7%BD%AE%E4%BE%8B%E5%AD%90
四、总结
传统的路由指的是:当用户访问一个url时,对应的服务器会接收这个请求,然后解析url中的路径,从而执行对应的处理逻辑。这样就完成了一次路由分发。
而前端路由是不涉及服务器的,是前端利用hash或者HTML5的history API来实现的,一般用于不同内容的展示和切换。