vue.js 路由原理理解
原理
更新视图但不重新请求页面
两种方法
- 利用URL中的hash(“#”)
- 利用History interface在HTML5中新增方法
vue- router实现模式
vue-router是Vue.js框架的路由插件,它是通过mode这一参数控制路由的实现模式的,在创建VueRouter实例对象是,mode以构造参数的形式传入,传入string类型指示history的类别,可用SupportPushState判断浏览器是否支持‘history’模式,两种方法都是在浏览器环境下使用,若不在浏览器环境下需强制使用‘abstract’模式。
根据mode判断确定history实例的类并实例化对应关系为:
history => HTML5Histoty
hash => HashHistory
abstract => AbstractHistory
HashHistory
hash(“#”)符号本身是用来加在URL指示网页中的位置,#本身以及它后面的字符称之为hash可通过window.location.hash属性读取。主要利用hash的以下特性:
- hash虽出现在URL但并不包括http请求中,用来指导浏览器动作,对服务器端无用。
- 可以为hash的改变添加监听事件:window.addEventListener(“hashchange”,fun,false)
- 每一次改变window.location.hash都会在浏览器访问历史中增加一个记录
利用hash的以上特点,就可以来实现前端路由"更新视图但不重新请求页面"的功能了
hash方式的路由有两个重要的方法:
HashHistory.push()
顾名思义push()方法最主要的是对window的hash进行了直接赋值。
HashHistory.replace()
replace()方法与push()方法不同之处在于,它并不是将新路由添加到浏览器访问历史栈顶,而是替换掉当前的路由;
监听地址栏
VueRouter.push()和VueRouter.replace()是可以在vue组件的逻辑代码中直接调用的,上述的第三种就是监听地址栏,即用户还可以直接在浏览器地址栏中输入改变路由,因此还需要监听浏览器地址栏中路由的变化 ,并具有与通过代码调用相同的响应行为,在HashHistory中这一功能通过setupListeners监听hashchange实现。
HTML5History
用到了HTML5新特性,需要浏览器的版本支持,前面也说过了通过SupportPushState来检查。与hash模式类似,只不过将window.location.hash()的直接进行赋值和window.location.replace()改为调用history.pushState()和history.replaceState()方法。
而HTML5History中添加修改浏览器地址栏URL的监听是在popState构造函数中执行的。
两种模式的比较
一般的需求场景中,hash模式与history模式是差不多的,调用history.pushState()相比于直接修改hash主要有以下优势:
pushState设置的新url可以是与当前url同源的任意url,而hash只可修改#后面的部分,故只可设置与当前同文档的url
pushState设置的新url可以与当前url一模一样,这样也会把记录添加到栈中,而hash设置的新值必须与原来不一样才会触发记录添加到栈中
pushState通过stateObject可以添加任意类型的数据记录中,而hash只可添加短字符串
pushState可额外设置title属性供后续使用
HTML5History模式存在的问题及解决办法
问题
在无#的history模式下,在地址栏修改URL会和正常URL一样向后端发出请求,若后端无配置的情况下,则会以前端传错参数返回404错误。
解决办法
如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。在 Vue 应用里面覆盖所有的路由情况,然后在给出一个 404 页面。或者,如果是用 Node.js 作后台,可以使用服务端的路由来匹配 URL,当没有匹配到路由的时候返回 404,从而实现 callback。
不管是HashHistory还是HTML5History这2种模式都是通过浏览器接口实现的,除此之外,vue-router还为非浏览器环境准备了一个abstract模式,其原理为用一个数组stack模拟出浏览器历史记录栈的功能。