路由
此处的路由指的是页面跳转的规则,通过不同的路径,来请求不同的资源,请求不同的页面是路由的其中一种功能。可以简单理解为url跳转
后端路由
和前端路由的url的访问意义有所不同,所有的url都会访问到服务器上对应的资源。页面请求的url全部要通过后端服务的过滤器进行过滤和处理
在之前学的web技术中,学习过Java Servlet,前端的页面资源和后端服务是放在了同一个项目文件中的,前端显示的页面都是后端渲染加工返回的
缺点:
前后端代码耦合比较深(尤其是在JSP),以此引发了特别多的缺点。
- 问题难以定位
- 每次跳转页面访问都要重新发起请求,体验较差,甚至对重复的css和js资源都要消耗网络请求时间,效率会有所降低
- 管理项目方面比较麻烦,代码可读性不高
前端路由(Vue)
现代前端开发中最流行的页面模型之一就是SPA单页应用架构。
单页应用的概念是伴随着 MVVM 出现的。单页面应用指的是应用只有一个主页面(index.html),通过动态替换DOM内容并同步修改url地址,来模拟多页应用的效果,切换页面的功能直接由前台脚本来完成,而不是由后端渲染完毕后前端只负责显示。
前端路由,顾名思义就是一个**前端不同页面的状态管理器,**可以不向后台发送请求而直接通过前端技术实现多个页面的效果。vue中的vue-router就是如此。这我们之后会解释原理
优点
- 解决了后端路由(也可以类比前后端耦合比较深)的缺点
- 组件化开发,对于前端的模块化开发也是很方便
缺点
- 前端路由一般对应的是客户端渲染,因此并不利于SEO(最重要的一点)
- 使用浏览器前进后退的时候回重新发送请求,没法合理利用缓存
- 单页面应用是无法记住之前滚动的位置的
前后端分离
在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制,由后端渲染页面或重定向
前端路由的出现,也让前后端分离开发的方式变的越来越主流,尤其是针对大型项目。
就笔者目前的情况而言,对此的理解仅仅限于在前后端分离的模式中,后端仅返回前端所需的数据,不再渲染HTML页面,不再控制前端的效果。至于前端用户看到什么效果,从后端请求的数据如何加载到前端中,都由前端自己决定,甚至是由用户自己决定。
也就是说前端和后端通过接口文档对接耦合
我们通常将后端开发的每个视图都称为一个接口,或者API,前端通过访问接口来对数据进行增删改查。这意味着,后端只需要关心数据接口的事务,更加专注于业务逻辑而不用理会前端的事务,这样能减轻工作压力,提高后端工作效率。
vue-router 主角
(1)vue-router
前面也提到过了,vue-router是Vue应用中的链接路径管理系统。与传统页面利用超链接不同,这是组件的切换,没法使用超链接跳转,因为我们只有一个页面。
更新视图而不重新请求页面,才是我们的核心。
(2)原理:Hash模式
vue-router 默认 hash 模式
2.1 url中#(hash)的含义
hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)
1.“#”代表网页中的一个位置。
其右面的字符,就是该位置的标识符。浏览器读取URL后,会自动将对应标识符的位置滚动至可视区域。
为网页位置指定标识符,有两个方法。一是使用锚点,二是使用id属性
2.HTTP请求不包括’#'
‘#’是用来指导浏览器动作的,对服务器端完全无用。在第一个#后面出现的任何字符,都会被浏览器解读为位置标识符。这意味着,这些字符都不会被发送到服务器端。
3.改变#不触发网页重载,但是会改变浏览器的访问历史
4.onhashchange事件
HTML 5新增的事件,当#值发生变化时,就会触发这个事件。
2.2 hash模式
使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页,也就是说hash 出现在 URL 中,但不会被包含在 http 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;所以说Hash模式通过锚点值的改变,根据不同的值,渲染指定DOM位置的不同数据。
hash 模式的原理是 onhashchange 事件(监测hash值变化),可以在 window 对象上监听这个事件。检测到 hash 的变化后,就可以通过替换 DOM 的方式来实现页面的更换。
图片来源:https://www.zhihu.com/question/53064386
(3)原理:HistoryAPI模式
当然,你可能会觉得#的存在使得url长得比较丑。。。。只需要在配置路由规则时,加入"mode: ‘history’",这种模式充分利用 HistoryAPI 来完成 URL 跳转而无须重新加载页面。
3.1 HTML5 History API
HTML5 History API是HTML5提供对history栈中内容的操作。DOM window对象通过history对象提供了对浏览器历史的访问。它暴露了很多有用的方法和属性,允许你在用户浏览历史中向前和向后跳转。另外也提供了一些很有意思的API。
- History.back():前往上一页,用户可点击浏览器左上角的返回按钮模拟此方法,等价于history.go(-1)
- History.forward():在浏览器历史记录里前往下一页,用户可点击浏览器左上角的前进按钮模拟此方法,等价于history.go(1)
- History.go():通过当前页面的相对位置从浏览器历史记录(会话记录)加载页面。比如,参数为-1的时候为上一页,参数为1的时候为下一页。当整数参数超出界限时,例如:如果当前页为第一页,前面已经没有页面了,我传参的值为-1,那么这个方法没有任何效果也不会报错。调用没有参数的go()方法或者不是整数的参数时也没有效果
- History.pushState():按指定的名称和URL(如果提供该参数)将数据push进会话历史栈,数据被DOM进行不透明处理;你可以指定任何可以被序列化的JavaScript对象
- History.replaceState():按指定的数据,名称和URL(如果提供该参数),更新历史栈上最新的入口。这个数据被DOM进行了不透明处理。你可以指定任何可以被序列化的JavaScript对象
3.2 History模式
HTML5的History API为浏览器的全局history对象增加的扩展方法。一般用来解决ajax请求无法通过回退按钮回到请求前状态的问题。
通过back(), forward(), go()等方法,我们可以读取浏览器历史记录栈的信息,进行各种跳转操作。pushState(), replaceState() 还可以对浏览器历史记录栈进行修改。当它们执行修改时,虽然改变了当前的 URL ,但浏览器不会立即向后端发送请求。
注意一点是:
不过这个模式还需要后台配置支持。如果后台没有正确的配置,有可能会返回 404。
所以要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面。