前言html
第一次接触这个是当年Twitter的改版,在访问页面路径中出现/!#类这样的结构。若是你的项目涉及到单页面的话,路由是必不可少的。今日早读文章由@陶自然受权分享。前端
正文从这开始~html5
什么是前端路由后端
路由,引导、指路之意。api
譬如咱们熟知的路由器,蹦跶在网络层的数据包转发设备,在网络中也是扮演着指路明灯的角色,肩负着将数据包正确导向目的地址的重任。浏览器
前端路由也借用了这个词,可是承担的工做全然不一样,它是服务于客户端浏览器的指路人。安全
所谓的前端路由,拥有这样一种能力:客户端浏览器能够不依赖服务端,根据不一样的URL渲染不一样的视图页面。服务器
前端路由的存在合理性网络
在Ajax之剑还未亮出,前端仍处于襁褓之中的时候,路由的工做交给了后端。在进行页面切换的时候,浏览器发送不一样的url请求;服务器接收到浏览器的请求时,经过解析不一样的url去拼接须要的html或者模板,而后将结果返回给浏览器端进行渲染。并发
服务器端路由也是不落俗套的有利亦有弊。它的好处是安全性更高,更严格得控制页面的展示。这在某些场景中是颇有用的,譬以下单支付流程,每一步只有在上一步成功执行以后才能抵达。这在服务器端能够为每一步流程添加验证机制,只有验证经过才返回正确的页面。那么前端路由不能实现每一步的验证?天然不是,姑且相信你的代码能够写的很严谨,保证正常状况下流程不会错,可是另外一个不得不面对的事实是:前端是毫无安全性可言的。用户能够肆意修改代码来进入不一样的流程,你可能会为此添加很多的处理逻辑。相较之下,固然是后端控制页面的进入权限更为安全和简便。
另外一方面,后端路由无疑增长了服务器端的负荷,而且须要reload页面,用户体验其实不佳。
这样,前端路由就有用武之地了。首先,它的出现无疑减轻了服务器端的压力。特别是对于一个比较复杂的应用来说,或者更确切的说,对于拥有一个复杂路由系统的应用来讲,服务器端须要为每个不一样的url执行一段处理逻辑在高并发的状况下实在有点不堪重负;其次,页面的切换能够不须要刷新整个页面了,没有网络延迟,没有闪烁刷新,提高了用户体验。
前端路由实现方式
既然目标实现,咱们须要解决的问题有哪些?咱们能够将问题拆的稍微细一点,先制定一个亿的小计划,实现以后再进行下一步:)
在页面不刷新的前提下实现url变化
捕捉到url的变化,以便执行页面替换逻辑
如何实现更新url而且页面不刷新
正如前面所说,前端路由相较于后端路由的一个特色就是页面在不彻底刷新的状况下进行视图的切换。页面url变了,可是并无从新加载!看上去彷佛有点难以想象,其实也没什么大不了。
试想将浏览器地址栏当作一个输入框,咱们须要实现的就是改变输入框的value可是不触发请求页面的操做,这样就不会从新加载新页面。假若输入框的值的变化和发送请求是一个原子操做,咱们也就一筹莫展了。庆幸的是,只有当咱们敲击了回车以后,请求才会被发送出去(这是显而易见的吧)。所以这就为咱们修改地址栏的值而不触发页面请求刷新创造了条件。BOM是否有提供修改浏览器地址栏url而不触发请求操做的方法呢?
这里,存在两种知足需求的方式。一是利用url中的hash字段;二是使用html5提供的history API。
hash方式
了解http协议就会知道,url的组成部分有不少,譬如协议、主机名、资源路径、查询字段等等,其中包含一个称之为片断的部分,以“#”为标识。
例如: http://www.gmail.com/text/#123,123即是url中的hash部分。
打开控制台,输入 location.hash,你能够获得当前url的hash部分(若是当前url不存在hash则返回空字符串)。接下来,输入 location.hash = '123',会发现浏览器地址栏的url变了,末尾增长了’#123’字段,而且,页面没有被从新刷新。很显然,这很符合咱们的要求。
history API
html5引入了一个history对象,包含了一套访问浏览器历史的api,能够经过window.history访问到它。
这里咱们看上了它的两个api方法:pushState 和 replaceState。
若上所示,它们接收彻底相同的参数,都是对浏览器的历史栈进行操做,将传递的url和相关数据压栈,并将浏览器地址栏的url替换成传入的url且不刷新页面(正中下怀!)。
By the way,不一样的地方是pushState 将指定的url直接压入历史记录栈顶,而 replaceState 是将当前历史记录栈顶替换成传入的数据。
这两种方式均可以帮咱们知足题设条件。采用哪种方式除了主观喜爱以外,还得依照客观事实:低版本的浏览器对于history API的兼容性很差,例如遇到了IE8,摆在眼前的道路彷佛就别无选择了。
如何跟踪url变化
在浏览器端,跟踪表单属性的变化通常都采用事件监听机制,跟踪url的变化也不落俗套。
对于hash方式的前端路由,一般能够监听 hashchange 事件,在事件回调中处理相应的页面视图展现等逻辑。
此外,html5提供的 popstate 事件也会在url的hash发生改变时触发。也就是说若是能够忽略低版本浏览器,咱们使用hash方式路由时也能够采用监听这个事件进行回调处理。
那么,若是是采用history API的形式呢?根据MDN的描述:
调用 history.pushState() 或者 history.replaceState() 不会触发 popstate 事件。popstate 事件只会在浏览器某些行为下触发, 好比点击后退按钮(或者在JavaScript中调用 history.back() 方法)。
这也就是说,咱们在使用history API改变浏览器的url时,仍须要额外的步骤去触发 popstate 事件,例如调用 history.back() 会 history.forward() 等方法。
从兼容性上来说,前面有说起hash的方式兼容性更好。然而,对于低版本的浏览器,例如IE6等等,不支持 hashchange 事件。这个时候咱们只能经过 setInterval 设置心跳的方式去模拟 hashchange。
一个简单实现
这里,给出一个很简单的实现:
router.js
index.html
index.js
一点总结
应用场景
前端路由大部分的应用场景,就是咱们如今熟知的单页应用SPA。
不存在纯前端路由
咱们此前所描述的前端路由,创建在已经打开了一个初始页面基础之上,而后在这个页面以内进行页面替换。然而,咱们如何进入这个初始页面?仅靠前端路由确定是力所不及。咱们至少要向后端发送一次http请求,接收所须要加载的页面不是吗?
因此,咱们并不能抛弃后端路由部分。这也意味着,咱们须要和后端确认各自的分工,哪些url归前端解析,哪些归后台解析。
关于本文
做者:@陶自然
原文:http://tomasran.space/archives/1bjDjwd2FgzJIsCyshbzag/
感谢前端早读课公众号推荐此文