路由模式
vue-router在实现单页面前端路由时,提供了三种方式:Hash模式、History模式、abstract模式,根据mode参数来决定采用哪一种方式
- hash: 使用 URL hash 值来作路由,默认模式
- history: 依赖 HTML5 History API 和服务器配置,查看 HTML5 History 模式
- abstract: 支持所有 JavaScript 运行环境,如node服务器端
Hash模式
vue-router 默认模式是 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,当 URL 改变时,页面不会去重新加载
hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分(/#/..),浏览器只会加载相应位置的内容,不会重新加载网页,也就是说 #是用来指导浏览器动作的,对服务器端完全无用,HTTP请求中不包括#;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;所以说Hash模式通过锚点值的改变,根据不同的值,渲染指定DOM位置的不同数据
History模式
HTML5 History API提供了一种功能,能让开发人员在不刷新整个页面的情况下修改站点的URL,就是利用 history.pushState API 来完成 URL 跳转而无须重新加载页面
由于hash模式会在url中自带#,如果不想要很丑的 hash,我们可以用路由的 history 模式,只需要在配置路由规则时,加入"mode: 'history'",这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面
abstract模式
abstract模式是使用一个不依赖于浏览器的浏览历史虚拟管理后端。
根据平台差异可以看出,在 Weex 环境中只支持使用 abstract 模式。 不过,vue-router 自身会对环境做校验,如果发现没有浏览器的 API,vue-router 会自动强制进入 abstract 模式,所以 在使用 vue-router 时只要不写 mode 配置即可,默认会在浏览器环境中使用 hash 模式,在移动端原生环境中使用 abstract 模式(也可以明确指定在所有情况下都使用 abstract 模式)
前端路由的两种实现方法
1.hash路由
class Routers {
constructor() {
// 以键值对的形式储存路由
this.routes = {}// 当前路由的URL
this.currentUrl = ''
// 记录出现过的hash
this.history = []
// 作为指针,默认指向this.history的末尾,根据后退前进指向history中不同的hash
this.currentIndex = this.history.length - 1
// 默认不是后退操作
this.isBack = falsethis.refresh = this.refresh.bind(this)
this.goBack = this.goBack.bind(this)
// 监听事件
window.addEventListener('load', this.refresh, false)
window.addEventListener('hashchange', this.refresh, false)
}
// 将path路径与对应的callback函数储存
route(path, callback = () => {}) {
this.routes[path] = callback
}
// 回退
goBack() {
this.isBack = true
this.currentIndex <= 0
? (this.currentIndex = 0)
: (this.currentIndex = this.currentIndex - 1)
location.hash = `#${this.history[this.currentIndex]}`
this.routes[this.history[this.currentIndex]]()
}
// 刷新
refresh() {
// 获取当前URL中的hash路径
this.currentUrl = window.location.hash.slice(1) || '/'
if (!this.isBack) {
// 如果不是后退操作,且当前指针小于数组总长度,直接截取指针之前的部分储存下来
// 此操作来避免当点击后退按钮之后,再进行正常跳转,指针会停留在原地,而数组添加新hash路由
// 避免再次造成指针的不匹配,我们直接截取指针之前的数组
// 此操作同时与浏览器自带后退功能的行为保持一致
if (this.currentIndex < this.history.length - 1) {
this.history = this.history.slice(0, this.currentIndex + 1)
this.history.push(this.currentUrl)
this.currentIndex++
}
}
this.routes[this.currentUrl]()
this.isBack = false
}
}
Router.route('/home', () => {
console.log('----home----')
})
Router.route('/about', () => {
console.log('----about----')
})
2.History路由
class Routers {
constructor() {
this.routes = {}
// 在初始化时监听popstate事件
this._bindPopState()
}
// 初始化路由
init(path) {
history.replaceState({path: path}, null, path)
this.routes[path] && this.routes[path]()
}
// 将路径和对应回调函数加入hashMap储存
route(path, callback = () => {}) {
this.routes[path] = callback
}
// 触发路由对应回调
go(path) {
history.pushState({path: path}, null, path)
this.routes[path] && this.routes[path]()
}
// 监听popstate事件
_bindPopState() {
window.addEventListener('popstate', e => {
const path = e.state && e.state.path
this.routes[path] && this.routes[path]()
})
}
}