前端路由(hash和history)
路由是根据不同的url地址来显示不同的页面或内容的功能,这个概念很早是由后端提出的。
后端之前是这么做的,当我们访问 http://xxx.abc.com/xx 的时候,大致流程可以想象成这样的:
1. 浏览器向服务器发出请求。
2. 服务器监听到80端口,如果有请求过来,那么就解析url地址。
3. 服务器根据客户端的路由配置,然后就返回相应的信息(比如html字符串、json数据或图片等)。
4. 浏览器根据数据包的 Content-Type来决定如何解析数据。
如上就是后端路由最初始的实现方式,那么既然有后端路由,那为什么还需要我们前端路由呢?后端路由有一个很大的缺点就是每次路由切换的时候都需要去刷新页面,然后发出ajax请求,然后将请求数据返回回来,那么这样每次路由切换都要刷新页面对于用户体验来说就不好了。因此为了提升用户体验,我们前端路由就这样产生了。它就可以解决浏览器不会重新刷新了。
history模式
用url规范的路由,但跳转时不刷新页面
HTML5的History API为浏览器的全局history对象增加了该扩展方法。它是一个浏览器的一个接口,在window对象中提供了onpopstate事件来监听历史栈的改变,只要历史栈有信息发生改变的话,就会触发该事件
在html5中,History API 新增了操作会话浏览历史记录的功能。如下新增的几个方法:
window.history.state. 该参数是只读的,表示与会话浏览历史的当前记录相关联的状态对象。如下图所示:
window.history.pushState(data, title, ?url): 在会话浏览历史记录中添加一条记录。
window.history.replaceState(data, title, ?url): 该方法用法和history.pushState方法类似,但是该方法的含义是将修改会话浏览历史的当前记录,而不是新增一条记录。也就是说把当前的浏览地址换成 replaceState之后的地址,但是浏览历史记录的总长度并没有新增
<!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="btn1">修改 url</button> <script> // 页面初次加载,获取 path document.addEventListener('DOMContentLoaded', () => { console.log('load', location.pathname) }) // 打开一个新的路由 // 【注意】用 pushState 方式,浏览器不会刷新页面 document.getElementById('btn1').addEventListener('click', () => { const state = { name: 'page1' } console.log('切换路由到', 'page1') history.pushState(state, '', 'page1') // 重要!! }) // 监听浏览器前进、后退 window.onpopstate = (event) => { // 重要!! console.log('onpopstate', event.state, location.pathname) } // 需要 server 端配合,可参考,vue-router官网 // 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 </script> </body> </html>
hash模式
hash 变化会触发网页跳转,即浏览器的前进,后退
hash 变化不会刷新页面,spa必须特点
hash 永远不会提交到server端(前端自生自灭)
hash路由模式是这样的:http://xxx.abc.com/#/xx。 有带#号,后面就是hash值的变化。改变后面的hash值,它不会向服务器发出请求,因此也就不会刷新页面。并且每次hash值发生改变的时候,会触发hashchange事件。因此我们可以通过监听该事件,来知道hash值发生了哪些变化
我们先来了解下location有哪些属性,如下: 复制代码 // 完整的url location.href // 当前URL的协议,包括 :; 比如 https: location.protocol /* 主机名和端口号,如果端口号是80(http)或443(https), 那就会省略端口号,比兔 www.baidu.com:8080 */ location.host // 主机名:比如:www.baidu.com location.hostname // 端口号;比如8080 location.port // url的路径部分,从 / 开始; 比如 https://www.baidu.com/s?ie=utf-8,那么 pathname = '/s'了 location.pathname // 查询参数,从?开始;比如 https://www.baidu.com/s?ie=utf-8 那么 search = '?ie=utf-8' location.search // hash是页面中的一个片段,从 # 开始的,比如 https://www.baidu.com/#/a/b 那么返回值就是:"#/a/b" location.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="btn1">修改 hash</button> <script> // hash 变化,包括: // a. JS 修改 url // b. 手动修改 url 的 hash,在浏览器器地址手动赋值 // c. 浏览器前进、后退 // onhashchange 事件在当前 URL 的锚部分(以 '#' 号为开始) 发生改变时触发 window.onhashchange = (event) => { //http://localhost:8080/01-hash.html console.log('old url', event.oldURL) //http://localhost:8080/01-hash.html#/user console.log('new url', event.newURL) // #/user console.log('hash:', location.hash) } // 页面初次加载,获取 hash document.addEventListener('DOMContentLoaded', () => { //http://localhost:8080/01-hash.html hash是空的 console.log('hash:', location.hash) }) // JS 修改 url document.getElementById('btn1').addEventListener('click', () => { location.href = '#/user' }) </script> </body> </html>
hash模式的特点:
hash模式在浏览器地址栏中url有#号这样的,比如(http://localhost:3001/#/a). # 后面的内容不会传给服务端,也就是说不会重新刷新页面。并且路由切换的时候也不会重新加载页面。
history模式的特点:
浏览器地址没有#, 比如(http://localhost:3001/a); 它也一样不会刷新页面的。但是url地址会改变。