SPA(单页面应用)需要在不刷新页面的情况下做页面更新的能力,这就需要引入前端路由,实际上,前端路由是利用了浏览器的hash或history属性。
一、什么是路由
1、路由用途解释:随浏览器地址的变化,展示给用户看到的页面也不同。
2、路由实现原理解释:URL到函数的映射
二、路由又分前端路由和后端路由:
-
后端路由: 又称服务器端路由,当服务器收到客户端发来的HTTP请求,就会根据请求的URL,来找到相应的映射函数,然后执行该函数,将执行结果的返回值发送给客户端。
对于最简单的静态资源服务器,可以认为,所有的URL的映射函数就是一个文件读取操作。而对于动态资源,映射函数可能是一个数据库读取操作,也可能是进行一些数据操作,等等。然后根据读取的数据,在服务器端就使用相应的模块来对页面进行渲染后,再返回渲染完毕的页面。这种方式在早期的前端开发中非常普遍,像京东的页面就是一个后端路由,他请求的是一个页面。
优点:安全性好,SEO好。
缺点:加大服务器的压力,不利于用户体验,代码冗合。 -
前端路由: URL到函数的映射。路由的映射函数通常是进行一些DOM的显示隐藏操作。当访问不同路径时,就会显示不同的页面组件。
优点:访问不同页面时,仅仅只是变换了路径而已,没有网络延迟,提升了用户体验。
缺点:使用浏览器的前进后退时,会重新发送请求,没有合理的利用缓存,不利于SEO。
三、前端路由主要有两种实现方案:hash、history API
1、Hash的实现原理
hash实现就是基于location.hash来实现的,早期前端路由都是用hash。location.hash的值就是URL中#后面的内容。比如百度网站设置他的location.hash=’#abc’,那么他的网址就是https://www.baidu.com/#abc。
1.1:hash特性:
①、 URL中hash值只是客户端的一种状态,即当客户端向服务器端发送请求时,hash部分是不会被发送的,对后端无影响所以改变hash不会重新加载啊页面。
②、 每次hash值发送改变,都会在浏览器的访问历史中新增一个记录,所以我们可以操作浏览器前进回退,其实就是操作前进回退按钮去控制hash值的切换。
③、 使用hashchange事件来监听hash的变化。还可以通过history.length看到路由总数。
④、 Hash本身用作页面定位(锚点),用作路由后后锚点功能就没有了,hash传参基于URL,数据量大时会有体积限制,在导航栏会出现很丑的‘#’
1.2:hash的使用
①、 使用a标签,设置href属性,点击后URL就会发生变化,触发hashchange事件。
<a href=‘#test’>test</a>
②、 使用js对location.hash进行赋值,来改变URL触发hashchange事件。
location.hash=‘#test’
举例:hash方案实现路由切换 —监听事件hashchange
window.addEventListener("hashchange", function() {
// 获取hash值
var hash = window.location.hash;
// 根据获取的hash做相应的操作
. . .
window.location.hash = "#hahah";
// 变成http://www.bbbb.com#hahah
});
每当hash发生改变都会触发hashchange方法,但是注意,浏览器刷新,页面跳到首页,URL不会改变。
2、history API 的实现原理
更美观的实现URL的变化,由H5提供的history API。最主要的API:history.pushState()、history.replaceState()。这两个API可以在不刷新的情况下,操作浏览器的历史记录。区别:pushState()是会增加新的历史记录,而replaceState()是替换当前的历史记录。都接受三个参数(state,title,URL)
1.1、API的使用:
window.history.pushState(state,title,URL)
//state:需要保存的数据,这个数据在触发popstate监听事件时,可以在event.state里获取
//title:标题,基本没用,一般传null
//URL:设定新的历史纪录的URL。新的URL与当前URL的origin必须是一样的(同源),否则会抛出错误。URL可以时绝对路径,也可以是相对路径。
//如当前URL是 https://www.baidu.com/a/,执行history.pushState(null, null, './qq/'),则变成 https://www.baidu.com/a/qq/,
//执行history.pushState(null, null, '/qq/'),则变成 https://www.baidu.com/qq/
window.history.replaceState(state,title,URL)
//与pushState 基本相同,但她是修改当前历史纪录,而 pushState 是创建新的历史纪录
1.2、其他API -----触发监听
window.history.back(); // 后退
window.history.forward(); // 前进
window.history.go(1); // 前进一部,-2回退两不,window.history.length可以查看当前历史堆栈中页面的数量
1.2、history API的使用 — popState()事件监听
window.addEventListenner(‘popstate’,function(event){
// 监听浏览器前进后退事件,pushState 与 replaceState 方法不会触发
});
注意:仅仅调用pushSatte()和replaceState()去改变URL是不会触发事件监听的,需要另外点击前进后退按钮才触发,即调用back()、go()等API
怎么确实监听pushSatte()和replaceState()?
可以创建2个全新的事件,事件名为pushState和replaceState,我们就可以在全局监听。
//创建全局事件
var _wr = function(type) {
var orig = history[type];
return function() {
var rv = orig.apply(this, arguments);
var e = new Event(type);
e.arguments = arguments;
window.dispatchEvent(e);
return rv;
};
};
//重写方法
history.pushState = _wr('pushState');
history.replaceState = _wr('replaceState');
//实现监听
window.addEventListener('replaceState',function(e){
console.log('THEYDIDITAGAIN!replaceState111111');
});
window.addEventListener('pushState',function(e){
console.log('THEYDIDITAGAIN!pushState2222222');
});
1.3、hash和history的区别
- hash--------------history
- 兼容更好--------------更正式美观
- 只修改#后面内容--------------可以设置同源下任意URL
- 新值不能与旧值相同,一样的不会触发动作将记录添加到栈中--------------新旧值可以相同,pushSate该添加的会添加到栈中
- 对服务器无需改动--------------刷新时,若服务器没有响应数据或资源,会404。需要对服务器做一些改造,对不同的路由进行相应的设置。
- 即不会发送请求--------------会向服务器发送请求,避免404服务器应该做处理。当匹配不到资源时,应返回同一个html页面