相信使用vue开发的前端er和我一样对vue-router不陌生。
但是就个人而言,每次用起来轻车熟路,包括懒加载都在项目使用,但是从未深究其原理。
这两天晚上一直在看前端路由方面的相关blog,结合自己的开发体验,写下了这篇个人总结,加深自己对这方面的知识掌握。
前言
犹记当初上班写的第一个前端项目,采用后端路由的方式,每次开发新页面时都需要先让后端分配一个路由地址,不然就是404了。
现在想想,其实前后端分离不仅仅是开发模式的分离,更是前后端的资源的分离。
路由简介
简单来说路由就是浏览器和服务器进行交互的一种方式,通过不同的路径请求不同的资源、页面是路由的主要功能。
资源就是我们能看到or看不到的js代码、图片、css样式、html结构、数据等
最开始路由是由后端控制的,因为web早期开发时php、jsp、asp等都是直接将页面和数据在后端生成后(SSR),再返回给浏览器reload页面进行渲染显示。
- 切换页面: 浏览器请求——等待——服务器响应,然后浏览器刷新
- 用户操作: 浏览器请求——等待——服务器响应,然后浏览器刷新
这样导致用户体验极差,
所以最开始网站大多以静态页面展示信息为主,如企业官网、新闻网站之流,哪有现在各种B/S架构系统这么风光。
而Ajax技术的兴起则彻底改变了这一切,Ajax让我们能够在不刷新浏览器的前提下刷新数据。
1996,微软首先提出 iframe 标签,iframe 带来了异步加载和请求元素的概念,随后在 1998 年,微软的 Outloook Web App 团队提出 Ajax 的基本概念(XMLHttpRequest的前身),并在 IE5 通过 ActiveX 来实现了这项技术。在微软实现这个概念后,其他浏览器比如 Mozilia,Safari,Opera 相继以 XMLHttpRequest 来实现 Ajax。(兼容问题从此出现,话说微软命名真喜欢用X,MFC源码一大堆。。)不过在 IE7 发布时,微软选择了妥协,兼容了 XMLHttpRequest 的实现。
有了 Ajax 后,用户操作后就不用再等待糟心的浏览器刷新,也为前端独立实现路由提供了可能。
前端路由实现原理
上面提到的Ajax解决了用户操作-刷新页面的问题,而前端路由解决了切换页面-刷新页面的问题
前端路由究其本质就是:
- 监听 url 的变化
- 截获new url地址
- 解析new url匹配路由规则
- 显示new url页面内容
但是这样有人就会问:url 每次变化不是都会刷新页面吗?页面都刷新了那和后端路由有什么区别?
所以要实现前端路由首先需要解决的是改变页面url不向后端发出请求。
第一种方法是通过 hash 的方式来实现url切换,因为hash的变化不会引起页面的刷新,hash后面的字符也不会发送给服务器。
第二种方法则是通过14年HTML5中History第一项新增的pushState、replaceState方法。
Hash路由
最开始hash其实是作为页面锚点出现的,实现点击某个链接后迅速定位到对应位置,见a标签-锚。
以上面url为例,此时hash值为 /test。它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全是透明的,因此改变 hash 不会重新加载页面。
1 | // 路由 |
上面是hash路由的简单demo,运行changeRoute方法同时会触发window.hashchange方法。
hash路由有以下缺点:
- 浏览器地址栏中显示的url一定会有一个#号
- 页面不能再使用书签跳转,占用了原来的书签锚点链接
与实现前端路由的伟大使命相比,这些缺点在之前是完全可以接受的。
History路由
History路由主要是使用了H5新增的pushState和replaceState两个方法实现来更改url,相较于hash,两者路由原理基本一致,可以看做是HTML5提供官方版本的前端路由。
1 | function changeRoute(path) { |
上面同样是history路由的简单demo
它也有一个需要注意的地方:刷新会从服务器请求当前url的资源从而导致404,所以需要后端将所有请求重定向到index,由前端控制是否真的404。
如何更改页面
我们知道,路由的目的是定位到相应页面,上面说的只是如何在不重新请求的情况下改变url,那么如何把页面内容改变为对应url的内容呢?
假设我们的web应用如下,app里放的是所有显示的内容:1
2
3
4
5
6
7
8
9
10
11
<html lang="en">
<head>
<title>lonhon.top</title>
</head>
<body>
<div id="app">
index
</div>
</body>
</html>
前端路由其实是在通过hash | history 改变url的同时将app节点innerHtml替换为对应html内容。
前端路由优缺点
优点
从性能和用户体验的层面来比较的话,后端路由每次访问一个新页面的时候都要向服务器发送请求,然后服务器再响应请求,这个过程肯定会有延迟。而前端路由在访问一个新页面的时候仅仅是变换了一下路径而已,没有了网络延迟,对于用户体验来说会有相当大的提升。
如上一个页面结构,navigator和header都是一样,我们切换页面实际上只是改变中间content的显示内容,页面较少时我们可以将全部content拿到,然后前端路由进行内容切换,对用户来说就是页面切换就是毫秒级响应。
如果使用 懒加载 的话,也可以忽略已有的navigator和header只从服务器拿content,从而减少http请求的传输内容。
缺点
无法刷新时无法记录当前滚动位置,不过现在vue-router和react-router都对这方面进行了完好的封装。
杂记
路由懒加载
路由懒加载就是在路由跳转到某个页面的时候再请求该页面的资源(和后端路由性质不同),比如index和product页面是高频页面,我们可以首次访问时就请求这两个页面的资源,后面切换就直接前端路由后加载,加快访问速度。
而other页面是低频页面,我们可以采用懒加载方式,访问的时候再请求,这样就能减小首次访问时所需的资源,从而提高访问速度。
页面404处理
使用前端路由时,我们一般会先建立一个路由表,存放所有路由信息,当访问路由表中没有注册的页面时,就可以返回404页面了。
meta
本文两种路由demo
vue-router hash路由源码
vue-router history路由源码-onpopstate
vue-router history路由源码-pushstate