前端路由

什么是前端路由
路由,引导、指路之意。

譬如我们熟知的路由器,蹦跶在网络层的数据包转发设备,在网络中也是扮演着指路明灯的角色,肩负着将数据包正确导向目的地址的重任。

前端路由也借用了这个词,但是承担的工作全然不同,它是服务于客户端浏览器的指路人。

所谓的前端路由,拥有这样一种能力:客户端浏览器可以不依赖服务端,根据不同的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/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容