前端路由的基本原理
前言
在开发单页Web应用(SPA)时,路由是重要环节。
SPA(single page web application) ,简单的说就是一个Web项目里只有一个HTML页面,利用JS动态的变换HTML的内容,从而来模拟多视图间跳转。
SPA提高了Web应用的交互体验,在与用户交互的过程中,不在需要重新刷新页面,获取数据也是通过Ajax异步获取,页面显示变得更加流畅。但页面的url没有变化,这导致了两个问题:
- SPA无法记住用户的操作记录,无论是刷新、前进还是后退,都无法展示用户真实的期望内容。
- 由于只有一个url,SEO不友好,不方便搜索引擎进行收录。
前端路由因此而产生。
什么是前端路由
路由是根据不同的 url 地址展示不同的内容或页面。
路由的概念来源于服务端,在服务端中路由描述的是 URL 与处理函数之间的映射关系。
而在 Web 前端单页应用中,路由描述的是 URL 与 UI 之间的映射关系,这种映射是单向的,即 URL 变化引起 UI 更新(无需刷新页面)。
简单的说,就是在保证只有一个HTML页面,且与用户交互时不刷新和跳转页面的同时,为SPA中的每一个视图展示形式匹配一个特殊的url,在刷新、前进、后退和SEO时均通过这个特殊的url来实现。改变url时不让浏览器向服务器发送请求,而且可以监听到url的变化。
前端路由的兴起就是把不同路由对应不同的内容或页面的任务交给前端来做,之前是通过服务端根据 url 的不同返回不同的页面来实现的。
还需搞清楚这几个概念
- 路由
- 分发:分别发送到各个地方,路由就是分发请求,路由都是一对多的(一个用户可以发送多个请求到不同地方)。分发请求的对象就是路由。
- 路由表:一个存储到各个目的地的最佳路径的表。路由根据路由表来传送,所有框架实现路由都有路由表。
- 默认路由:如果没有给任何路径,则给默认值。
- 404 路由 / 保底路由:如果用户输入了错误路径,就给一个404页面,保证用户总能看到一个页面。
- 嵌套路由:如果界面里还有几块子界面,那就不能在App里面路由,只能在该界面里做路由。
hash 模式
这里的hash就是指url后的#号以及后面的字符,比如说”https://www.baidu.com/#dhoarhiqw9uw“,其中“#dhoarhiqw9uw”就是hash值。
由于hash值的变化不会导致浏览器向服务器发送请求,而且hash的改变会触发hashchange事件,浏览器的前进后退也能对其进行控制。
window.location.hash //获取当前的hash值
window.addEventListener('hashchange',function(){
//监听hashchange事件,用于改变url
})
优点:完全前端路由,只改变#后面的值,无刷新。兼容性好,可以兼容到IE8;无需服务端配合处理非单页的url地址。
缺点:SEO不友好,看起来丑,会导致锚点功能失效。相同 hash 值不会触发动作将记录加入到历史栈中,而 pushState 则可以。
google出了一种方式hashbang能够让服务求收到hash的请求,前提是需要在#号前面加上!号。类似于:baidu.com!#aaa,虽然这种方法是可行的但是依然不能和以前的SEO相比。
history模式
History 接口允许操作浏览器的曾经在标签页或者框架里访问的会话历史记录。
window.location.pathname//获取/路径字段
history.back()
history.go()
history.forward()//完成后退前进等操作
history.pushState();// 添加新的状态到历史状态栈
history.replaceState() // 用新的状态代替当前状态
history.state // 返回当前状态对象
history.pushState() 和 history.replaceState() 均接收三个参数(state, title, url)
- state:合法的 Javascript 对象,可以用在 popstate 事件中
- title:现在大多浏览器忽略这个参数,可以直接用 null 代替
- url:任意有效的 URL,用于更新浏览器的地址栏
popstate事件
当活动历史记录条目更改时,将触发popstate事件。如果被激活的历史记录条目是通过对history.pushState()的调用创建的,或者受到对history.replaceState()的调用的影响,popstate事件的state属性包含历史条目的状态对象的副本。
需要注意的是调用history.pushState()或history.replaceState()不会触发popstate事件。只有在做出浏览器动作时,才会触发该事件,如用户点击浏览器的回退按钮(或者在Javascript代码中调用history.back()或者history.forward()方法)。
history.pushState() 和 history.replaceState() 的区别在于:
- history.pushState() 在保留现有历史记录的同时,将 url 加入到历史记录中。
- history.replaceState() 会将历史记录中的当前页面历史替换为 url。
由于 history.pushState() 和 history.replaceState() 可以改变 url 同时,不会刷新页面,所以在 HTML5 中的 histroy 具备了实现前端路由的能力。
优点:在同源(需要后端服务器的配合,将所有前端路由渲染至一个页面)的情况下,实现了前端完全自由,stateObject可以是任何数据类型,URL可以是相对路径也可以是绝对路径。
缺点:如果后端没有做对应的路由,在刷新时会出现404。IE8以下不支持。
memory模式
memory 模式的实现不依赖于 url的变化,就是说,页面内容切换,url始终保持不变,实现方法就是使用 window.localStorage存储当前路径即可(把路径存在localstronge中,需要切换路由时就去localstronge中获取;改变路径的时候就将路径存在localsstronge中,因此url中的路径不会改变)。这种方式不适合网页应用,url 信息是存储到本地的,无法准确分享页面,因此只适合单机应用。在前端路由中一般不适用。
Vue Router
Vue Router 是 Vue.js (opens new window)官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于 Vue.js 过渡系统的视图过渡效果
- 细粒度的导航控制
- 带有自动激活的 CSS class 的链接
- HTML5 历史模式或 hash 模式,在 IE9 中自动降级
- 自定义的滚动条行为