VueRouter路由模式解析
VueRouter路由模式解析
前端路由的实现方式主要有两种:hash
模式和history
模式。
hash模式
在window.location
对象中有一个hash
字段,可以获取地址栏中#
字符及后边的所有字符。
hash
也称作锚点,本身是用来做页面定位的,可以使对应id
的元素显示在可是区域内。
比如说下面这张动图,通过锚点直接跳转到footer
:
hash
虽然出现在 URL
中,但不会被包括在 HTTP
请求中,不会对请求有影响。
下图可以看到虽然地址是http://localhost:3000/index.html#footer
,但是network
中的请求是http://localhost:3000/index.html
。
由于hash
值变化不会导致浏览器向服务器发出请求,而且hash
改变会触发hashchange
事件,浏览器的进后退也能对其进行控制,所以在 html5
的 history
出现前,开发者基本都是使用 hash
来实现前端路由的。
history模式
HTML5
规范提供了history.pushState
和history.replaceState
来进行路由控制。通过这两个方法可以改变url
且不向服务器发送请求。同时不会像hash
有一个#
,更加的美观。但是如果刷新页面,那么请求的资源就是当前地址栏中的地址了,对于SPA
应用来说就需要进行配置将所有的路由重定向到根页面。
调用pushState
跳转到相同的路由时仍可以成功且路由栈数量会加1。
这个可以重写pushState
方法来进行过滤。
const stack = [];
const originPushState = window.history.pushState;
window.history.pushState = function() {if(stack[stack.length - 1] === arguments[2]) {return;}stack.push(arguments[2])originPushState.call(history, ...arguments);
}
history.replaceState
和 history.pushState
却不会触发 popstate
事件,不过可以手动创建一个PopStateEvent
并触发该事件。
function createPopStateEvent(state, title) {return new PopStateEvent("popstate", {state: state,title: title});
}window.history.pushState = function() {if(stack[stack.length - 1] === arguments[2]) {return;}stack.push(arguments[2])window.dispatchEvent(createPopStateEvent(...arguments));originPushState.call(history, ...arguments);
}
VueRouter中的路由模式
文章中介绍的vue-router
源码版本为v3.4.9
。
hash模式
在hash
模式中,VueRouter
主要还是以history.pushState
为首选,在不支持history
的浏览器中才会通过改变location.hash
的值来实现路由切换。
在源码中的hash.js
文件中的pushHash
方法明确定义。
// src/history/hash.js
function pushHash (path) {if (supportsPushState) {pushState(getUrl(path))} else {window.location.hash = path}
}
同时在beforeCreate
监听hashchange
方法,防止用户直接在地址栏上修改url
。通过点击跳转的方式VueRouter
做了处理并不会触发该方法。
const eventType = supportsPushState ? 'popstate' : 'hashchange'
window.addEventListener(eventType,handleRoutingEvent
)
hash
模式为什么首先考虑使用history.pushState
呢?
因为通过history.pushState
可以设置state
值,VueRouter
在每个路由跳转时带有唯一的key
,可以用于在浏览器后退前进时恢复到之前的滚动的位置。
在源码中的pushState
方法中可以看到,在跳转前保存当前路由的滚动条位置,同时为跳转路由添加一个新key
标识新路由。function pushState (url?: string, replace?: boolean) {saveScrollPosition()const history = window.history// safari存在问题,路由栈中只能保存100,超过100个异常捕获用location来替换路由对象try {if (replace) {const stateCopy = extend({}, history.state)stateCopy.key = getStateKey()history.replaceState(stateCopy, '', url)} else {history.pushState({ key: setStateKey(genStateKey()) }, '', url)}} catch (e) {window.location[replace ? 'replace' : 'assign'](url)} }
history
模式
在初始化history
模式时,监听popstate
,在路由变化时恢复滚动条位置。
// src/history/html5.js
this.transitionTo(location, (route) => {if (supportsScroll) {handleScroll(router, route, current, true)}
})
window.addEventListener('popstate', handleRoutingEvent)
前面提到history.pushState
和history.replaceState
两个方法不会触发popstate
方法,因此在push
和replace
方法中,在路由切换成功后手动执行hashScroll
方法。
// src/history/html5.js
push(location: RawLocation, onComplete?: Function, onAbort?: Function) {const { current: fromRoute } = thisthis.transitionTo(location,(route) => {pushState(cleanPath(this.base + route.fullPath))handleScroll(this.router, route, fromRoute, false)onComplete && onComplete(route)},onAbort)}
abstract
模式
在VueRouter
中除了hash
和history
两种模式外,还新增了一个abstract
模式,用来在不支持浏览器的环境中充当一个备用方案(例如Weex
)。
在abstract
模式中新建了一个对象用来模拟浏览器中路由栈。
this.stack = []
同时提供了三个路由跳转方法push
、replace
和go
,这三种方法跟hash
和history
模式中的push
、replace
和go
方法类似,来看看是怎么实现的。
// src/history/abstract.js push()方法
route => {// 在路由栈中添加一个新路由this.stack = this.stack.slice(0, this.index + 1).concat(route)this.index++onComplete && onComplete(route)
}
因为非浏览器环境中没有前进后退按钮,因此replace
其实就是替换掉路由栈中的最后一个路由。
// src/history/abstract.js replace()方法
route => {// 在路由栈中替换掉最后一个路由this.stack = this.stack.slice(0, this.index).concat(route)this.index++onComplete && onComplete(route)
}
在go
方法中同样对传入的数字进行判断是否在路由栈的范围内,否则不执行。
// src/history/abstract.js go()方法
const targetIndex = this.index + n
if (targetIndex < 0 || targetIndex >= this.stack.length) {return
}
之后直接将路由索引指向需要跳转的路由索引同时更新当前路由。
// src/history/abstract.js go()方法
const route = this.stack[targetIndex]
this.confirmTransition(route,() => {this.index = targetIndexthis.updateRoute(route)// ...
)// src/history/base.js
updateRoute(route: Route) {this.current = routethis.cb && this.cb(route)
}
无论是hash
还是history
模式都需要对浏览器当前的URL
产生影响,通过与abstract
结合也可以实现在已存在的路由页面中内嵌其他的路由页面,而保持在浏览器当中依旧显示当前页面的路由path
。
比如定义了一个hash
模式并存在两个路由的实例挂载在app
上,其中第二个路由中又定义一个abstract
模式的路由。这时候切换/route1
和/route2
并不会影响URL
。
const routes = [{path: '/',component: { template: `<div>default view</div>` }},{path: '/abstractRoute',component: {name: "abstract",template: '<div><h1 @click="toRoute(1)">跳转到router1</h1><h1 @click="toRoute(2)">跳转到router2</h1><router-view></router-view></div>',methods: {toRoute(num) {this.$router.push(`/route${num}`);}},router: new VueRouter({routes: [{path: '/route1',component: {template:'<h1>abstract route 1</h1>'}},{path: '/route2',component: { template:'<h1>abstract route 2</h1>'}},],mode: 'abstract'})}},
]const app = new Vue({router: new VueRouter({routes,mode: 'hash'}),template: `<div><router-link to="/">to /</router-link><router-link to="/abstractRoute">to abstractRoute</router-link><router-view></router-view></div>`,
}).$mount('#app')
VueRouter路由模式解析相关推荐
- vue-router路由模式详解
一.路由模式解析 要讲vue-router的路由模式,首先要了解的一点就是路由是由多个URL组成的,使用不同的URL可以相应的导航到不同的位置. 如果有进行过服务器开发或者对http协议有所了解就会知 ...
- vue-router路由模式
大家早上好,最近事比较多比较忙所以没有及时的更新博客,望大家谅解. 路由模式解析 这里要讲vue-router的路由模式,首先要了解的一点就是路由是由多个URL组成的,使用不同的URL可以相应的导航到 ...
- vue-router路由模式有几种?
vue-router路由模式有几种? vue-router有3种路由模式:hash,history,adstract. hash:使用URL hash值来做路由.支持所有浏览器,包括不支持HTML5 ...
- vue-router路由模式的区别和原理
vue-router路由模式 一.vue-router前端路由有两种模式,hash模式和history模式 hash模式 就是指 url 后面的 # 号以及后面的字符.每次刷新页面时是直接更改 # 后 ...
- vue-router 路由模式
vue-router 路由模式有哪几种? 有三种. 1. Hash 模式: 使用URL 的 hash 值来作为路由,支持所有浏览器 1.1 url 路径会出现 # 号字符 1.2 hash值 ...
- vue-router 路由模式有⼏种?
vue-router 有 3 种路由模式:hash.history.abstract对应的源码如下所示: switch (mode) {case 'history':this.history = ne ...
- Vue的三种路由模式
路由模式解析 这里要讲vue-router的路由模式,首先要了解的一点就是路由是由多个URL组成的,使用不同的URL可以相应的导航到不同的位置.如果有进行过服务器开发或者对http协议有所了解就会知道 ...
- Kubernetes网络技术解析之Pod基于路由模式的通信实现
前言 Kubernetes集群内,Pod之间可以通信,是Kubernetes网络实现的重要场景之一. Kubernetes通过CNI提供统一的接口和协议,使得我们在使用中可以根据需求自行选择不同的网络 ...
- vue两个html入口路由串了,vue-router路由与页面间导航实例解析
vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用.vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来.传统的页面应 ...
最新文章
- Lucene源代码学习之 PackedInts
- iOS 11开发教程(四)iOS11模拟器介绍一
- CSS实战经验:灵活运行注释带来的益处(转载)
- php 判断设备来源,PHP判断移动设备来源的方法
- mysql header files_编译安装php Cannot find MySQL header files under /usr/include/mysql.
- public,protected,private
- 面试必会之ArrayList源码分析手写ArrayList
- java学习class5
- 怎么使用biopython_Biopython - 简介
- 喝咖啡的好处和坏处好处
- freemarker导出excel单元格内换行
- 史上最全的数学建模竞赛介绍,大家不要错过哦!!!
- 2020 GDUT Rating Contest III (Div. 2) B - Loan Repayment 题解
- keil错误和解决办法(1):FCARM - Output Name not specified, please check ‘Options for Target - Utilities’
- 中科院计算机学院考研2021,2021中国科学院大学研究生分数线一览表(含2019-2020历年复试分数线)...
- 卸载oracle方法
- db2 reorg到底需要多少表空间
- Swift 中的类与结构体
- leetcode136---异或运算的交换律
- api格式_api平台支持的格式
热门文章
- 一键备份脚本backup.sh
- vuejs 数组定义字段_一个漂亮的文本字段,用于格式化VueJS制作的电话号码
- Java基础 - AO BO DO PO VO DAO DTO POJO
- 边界函数(decision boundary)
- Unity中常用到的基础函数
- 42步进电机转速力矩曲线_步进电机的力矩与转速
- linux中execve的用法,Linux 的 execve 函数
- Java把文件压缩成.zip压缩包和解压.zip压缩包(ZipOutputStream、ZipInputStream)
- 使用FeatureTask多线程优化in,提高查询速度
- 一个html5表格代码