??php
原文发于个人博客:https://github.com/hwen/blogS...html
路由这个概念最早是后端出现的。在之前用模板引擎开发页面时,常常会看到这样前端
http://hometown.xxx.edu.cn/bbs/forum.php
有时还会有带.asp
或.html
的路径,这就是所谓的SSR(Server Side Render),经过服务端渲染,直接返回页面。vue
其响应过程是这样的html5
1.浏览器发出请求git
2.服务器监听到80端口(或443)有请求过来,并解析url路径github
3.根据服务器的路由配置,返回相应信息(能够是 html 字串,也能够是 json 数据,图片等)ajax
4.浏览器根据数据包的Content-Type
来决定如何解析数据vue-router
简单来讲路由就是用来跟后端服务器进行交互的一种方式,经过不一样的路径,来请求不一样的资源,请求不一样的页面是路由的其中一种功能。npm
前端路由的出现要从 ajax 开始,为何?且听下面分析 (ˉ▽ ̄~)
Ajax,全称 Asynchronous JavaScript And XML,是浏览器用来实现异步加载的一种技术方案。在 90s 年代初,大多数的网页都是经过直接返回 HTML 的,用户的每次更新操做都须要从新刷新页面。及其影响交互体验,随着网络的发展,迫切须要一种方案来改善这种状况。
1996,微软首先提出 iframe 标签,iframe 带来了异步加载和请求元素的概念,随后在 1998 年,微软的 Outloook Web App 团队提出 Ajax 的基本概念(XMLHttpRequest的前身),并在 IE5 经过 ActiveX 来实现了这项技术。在微软实现这个概念后,其余浏览器好比 Mozilia,Safari,Opera 相继以 XMLHttpRequest 来实现 Ajax。(? 兼容问题今后出现,话说微软命名真喜欢用X,MFC源码一大堆。。)不过在 IE7 发布时,微软选择了妥协,兼容了 XMLHttpRequest 的实现。
有了 Ajax 后,用户交互就不用每次都刷新页面,体验带来了极大的提高。
但真正让这项技术发扬光大的,(。・∀・)ノ゙仍是后来的 Google Map,它的出现向人们展示了 Ajax 的真正魅力,释放了众多开发人员的想象力,让其不只仅局限于简单的数据和页面交互,为后来异步交互体验方式的繁荣发展带来了根基。
而异步交互体验的更高级版本就是 SPA(那么问个问题,异步交互最高级的体验是什么?会在文末揭晓)—— 单页应用。单页应用不只仅是在页面交互是无刷新的,连页面跳转都是无刷新的,为了实现单页应用,因此就有了前端路由。
单页应用的概念是伴随着 MVVM 出现的。最先由微软提出,而后他们在浏览器端用 Knockoutjs
实现。但这项技术的强大之处并未当时的开发者体会到,多是由于 Knockoutjs
实现过于复杂,致使没有大面积的扩散。
一样,此次接力的选手依然是 Google。Google 经过 Angularjs 将 MVVM 及单页应用发扬光大,让前端开发者可以开发出更加大型的应用,职能变得更大了。(不得不感慨,微软 跟 Google 都是伟大的公司)。随后都是你们都知道的故事,前端圈开始获得了爆发式的发展,陆续出现了不少优秀的框架。
原本还想写更多的。。。不过有点慢慢偏离主题了(下次会专门写写)
前端路由的实现其实很简单。
本质上就是检测 url 的变化,截获 url 地址,而后解析来匹配路由规则。
可是这样有人就会问:url 每次变化都会刷新页面啊?页面都刷新了,JavaScript 怎么检测和截获 url?
在 2014 年以前,你们是经过 hash 来实现路由,url hash 就是相似于
https://segmentfault.com/a/1190000011956628#articleHeader2
这种 #
。后面 hash 值的变化,并不会致使浏览器向服务器发出请求,浏览器不发出请求,也就不会刷新页面。另外每次 hash 值的变化,还会触发 hashchange
这个事件,经过这个事件咱们就能够知道 hash 值发生了哪些变化。
让咱们来整理思路,假如咱们要用 hash 的模式实现一个路由,那么流程应该是这样的。
hash 的实现相对来讲要简单方便些,并且不用服务器来支持。
另外咱们能够参考参考 vue-router 这一部分的实现(为了便于解释我简化了部分代码)
/** * 添加 url hash 变化的监听器 */ setupListeners () { const router = this.router /** * 每当 hash 变化时就解析路径 * 匹配路由 */ window.addEventListener('hashchange', () => { const current = this.current /** * transitionTo: * 匹配路由 * 并经过路由配置,把新的页面 render 到 ui-view 的节点 */ this.transitionTo(getHash(), route => { replaceHash(route.fullPath) }) }) }
检测到 hash 的变化后,就能够经过替换 DOM 的方式来实现页面的更换。
14年后,由于HTML5标准发布。多了两个 API,pushState
和 replaceState
,经过这两个 API 能够改变 url 地址且不会发送请求。同时还有 onpopstate
事件。经过这些就能用另外一种方式来实现前端路由了,但原理都是跟 hash 实现相同的。用了 HTML5 的实现,单页路由的 url 就不会多出一个#
,变得更加美观。但由于没有 #
号,因此当用户刷新页面之类的操做时,浏览器仍是会给服务器发送请求。为了不出现这种状况,因此这个实现须要服务器的支持,须要把全部路由都重定向到根页面。具体能够见:HTML5 histroy 模式
一样,咱们来理清下思路,这样写起代码才更驾轻就熟~
这部分 vue-router 的源码,能够发现实现的思路大致也是相同的
export class HTML5History extends History { constructor (router, base) { super(router, base) /** * 原理仍是跟 hash 实现同样 * 经过监听 popstate 事件 * 匹配路由,而后更新页面 DOM */ window.addEventListener('popstate', e => { const current = this.current // Avoiding first `popstate` event dispatched in some browsers but first // history route not updated since async guard at the same time. const location = getLocation(this.base) if (this.current === START && location === initLocation) { return } this.transitionTo(location, route => { if (supportsScroll) { handleScroll(router, route, current, true) } }) }) } go (n) { window.history.go(n) } push (location, onComplete, onAbort) { const { current: fromRoute } = this this.transitionTo(location, route => { // 使用 pushState 更新 url,不会致使浏览器发送请求,从而不会刷新页面 pushState(cleanPath(this.base + route.fullPath)) onComplete && onComplete(route) }, onAbort) } replace (location, onComplete, onAbort) { const { current: fromRoute } = this this.transitionTo(location, route => { // replaceState 跟 pushState 的区别在于,不会记录到历史栈 replaceState(cleanPath(this.base + route.fullPath)) onComplete && onComplete(route) }, onAbort) } }
我用纯 ES6 写了个前端的路由,没有用任何框架,就能够实现前端路由的全部功能~
固然,实现的思路就是上面的那两幅流程图。
你还能够经过 npm 来安装这个包(功能已经实现完整,并有详细文档)
npm i --save sme-router
以为有帮助的,请点个 star ~~
异步交互的最高级体验是什么?
PWA,让前端页面能够作到离线操做(是否是愈来愈像原生 app 了?)
以为有帮助的话,请点个赞,点个 star ~~
但愿看到更多干货的话,(●'◡'●) 快来关注个人杂货铺吧?