浅谈前端路由

关于秋招的一些感想

最近一段时间忙着秋招,一路经历了阿里终面挂,美团终面挂等等,感觉自己有点苦逼(尤其是因为没HC而挂是最难受的)。虽然到现在还没得到满意的结果,但这个过程还是有所收获的,这是虽然一个自我怀疑的过程,但也是一个不断弥补自身不足,学习的过程,其中与一些面试我的师兄在交流的过程中也是受益匪浅,并且也对自身以后要走的路有了一个更加明确的认识,所以前途漫漫还需努力呀!

一、路由

在现代前端开发中,路由是非常重要的一环。但路由到底是什么呢?有些说:路由就是指随着浏览器地址栏的变化,展示给用户的页面也不相同。这是从路由的用途上来解释路由是什么的,还有一种说法是:路由就是URL到函数的映射。这是从路由的实现原理上来解释路由是什么的。这两种说法都很有道理,但我个人认为还是第二种比较切合我自己对路由的理解吧。

上面已经说了上面是路由,而路由本身也经历了不同的发展阶段:

  1. 后端路由
  2. 前端路由

后端路由又可称之为服务器端路由,因为对于服务器来说,当接收到客户端发来的HTTP请求,就会根据所请求的相应URL,来找到相应的映射函数,然后执行该函数,并将函数的返回值发送给客户端。对于最简单的静态资源服务器,可以认为,所有URL的映射函数就是一个文件读取操作。对于动态资源,映射函数可能是一个数据库读取操作,也可能是进行一些数据的处理,等等。然后根据这些读取的数据,在服务器端就使用相应的模板来对页面进行渲染后,再返回渲染完毕的页面。这种方式在早期的前端开发中非常普遍,它的好处与坏处都很明显:

  • 好处:安全性好,SEO好。
  • 缺点:加大服务器的压力,不利于用户体验,代码冗合。

也正是由于后端路由还存在着自己的不足,前端路由才有了属于自己的一片天地与发展的空间。对于前端路由来说,路由的映射函数通常是进行一些DOM的显示和隐藏操作。这样,当访问不同的路径的时候,会显示不同的页面组件。前端路由主要有以下两种实现方案:

  • hash
  • history API

当然,前端路由也存在缺陷:使用浏览器的前进,后退键时会重新发送请求,来获取数据,没有合理地利用缓存。但总的来说,现在前端路由已经是实现路由的主要方式了,我们常用的诸如react-router等前端框架的路由控制都是基于前端路由进行开发的,因此将前端路由进行一个了解
还是很有必要的。

二、前端路由的实现

2.1 基于hash

早期的前端路由的实现就是基于location.hash来实现的。其实现原理也很简单,location.hash的值就是URL中#后面的内容。比如下面这个网站,它的location.hash='#me':

https://www.srtian.com#me

此外,hash也存在下面几个特性:

  • URL中hash值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash部分不会被发送。
  • hash值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash的切换。
  • 我们可以使用hashchange事件来监听hash的变化。

出发hsah变化的方式也有两种,一种是通过a标签,并设置href属性,当用户点击这个标签后,URL就会发生改变,也就会触发hashchange事件了:

<a href="#srtian">srtian</a>

还有一种方式就是直接使用JavaScript来对loaction.hash进行赋值,从而改变URL,触发hashchange事件:

location.hash="#srtian"

2.2 基于History API

前面的hash虽然也很不错,但使用时都需要加上#,并不是很美观。因此到了HTML5,又提供了History API来实现URL的变化。其中做最主要的API有以下两个:history.pushState()和history.repalceState()。

这两个API可以在不进行刷新的情况下,操作浏览器的历史纪录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录。此外,这两个api都接受三个参数:

window.history.pushState(null, null, "http://www.163.com");
  • 状态对象(state object):一个JavaScript对象,与用pushState()方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,会触发popstate事件,并能在事件中使用该对象。
  • 标题(title):一般浏览器会忽略,最好传入null。
  • 地址(URL):就是需要新增的历史记录的地址,浏览器不会去直接加载改地址,但后面也可能会去尝试加载该地址。此外需要注意的是,传入的URL与当前URL应该是同源的。

这一块的详情可以去看MDN,它做了一个比较详细的介绍:

https://developer.mozilla.org/en-US/docs/Web/API/History

此外,还提供了popstate事件来监听历史记录的变化。

可以看看下面这个实例:

<p id="example">
 <a href="/name" title="name">name</a>
 <a href="/age" title="age">age</a>?
</p>
<div class="main" id="main"></div>
<script>
;(function(){
    var examplebox = document.getElementById('example')
    var mainbox = document.getElementById('main')
    
    examplebox.addEventListener('click', function(e){
        e.preventDefault()
        var elm = e.target
        var uri = elm.href
        var tlt = elm.title
        history.pushState({path:uri,title:tlt}, null, uri)
        mainbox.innerHTML = 'current page is '+tlt
    })
    window.addEventListener('popstate',function(e){
        var state = e.state
        mainbox.innerHTML = 'current page is ' + state.title
    })
})()
</script>

两种实现方式的对比:基于Hash的路由实现,兼容性更好;而基于History API的路由,则更正式,更美观,可以设置与当前URL同源的任意URL,路径更直观。此外,基于Hash的路由不需要对服务器做改动,基于History API的路由需要对服务器做一些改造,需要对不同的路由进行相应的设置才行。

三、React-Router

由于我现在也就对React-Router比较熟悉,Vue学了太久了,忘记了。Angular刚学,还没到路由这块这来,因此就以React-Router为例,来聊聊现代前端框架的路由实现思路。先来看看一个简单的React中的Router代码:

<Router>
    <Switch>
        <Route path="/about" component={About}/> 
        <Route path="/:user" component={User}/> 
    </Switch> 
</Router>

其实现思路也很简单如下图所示:


image

其实现思路很简单:About和User这两个component一直都存在。当路由发生改变时,与URL相匹配的component机会被成功渲染。而不匹配的component就设置为null。

具体实现,大家可以看这篇文章,这位大佬做了很详细的介绍:

https://github.com/youngwind/blog/issues/109

参考资料:

https://github.com/youngwind/blog/issues/109

https://zhuanlan.zhihu.com/p/24814675

https://segmentfault.com/a/1190000007238999

http://www.cnblogs.com/yuqing6/p/6731980.html

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

推荐阅读更多精彩内容