Vue——Vue-router有⼏种模式?
Vue-router有⼏种模式?如何实现?
  Vue-router 是vue框架的路由插件。
  Vue-router 有两种模式:Hash 模式和History 模式。在开发的时候可以通过使⽤在路由配置中配置mode这个属性的值来配置使⽤哪种路由,如果不配置这个字段就默认是hash 模式。
  * Hash 模式:该模式有⼀个很明显的标志就是URL 中带有 #,我们可以通过window.location.hash 来获取这个值。
  * History 模式:该模式是由h5 提供的history 对象实现的。
  我们可以通过源码来看看路由是怎么实现的:
路由模式参数:
  在Vue-router 中是通过mode 这⼀个参数来实现控制路由的实现模式的:
const router = new VueRouter({
mode: 'history',
// 配置路由
routes:[...]
})
  在创建路由的实例中,我们通过mode参数指定当前创建路由的⽅式,我们可以通过VueRouter 类的定义来⼊⼿:
export default class VueRouter {
mode: string; // 传⼊的字符串参数,指⽰history类别
history: HashHistory | HTML5History | AbstractHistory; // 实际起作⽤的对象属性,必须是以上三个类的枚举
fallback: boolean; // 如浏览器不⽀持,'history'模式需回滚为'hash'模式
constructor (options: RouterOptions = {}) {
let mode = de || 'hash' // 默认为'hash'模式
this.fallback = mode === 'history' && !supportsPushState // 通过supportsPushState判断浏览器是否⽀持'history'模式
if (this.fallback) {
mode = 'hash'
}
if (!inBrowser) {
mode = 'abstract' // 不在浏览器环境下运⾏需强制为'abstract'模式
}
// 根据mode确定history实际的类并实例化
switch (mode) {
case 'history':
this.history = new HTML5History(this, options.base)
break
case 'hash':
this.history = new HashHistory(this, options.base, this.fallback)
break
case 'abstract':
this.history = new AbstractHistory(this, options.base)
break
default:
if (v.NODE_ENV !== 'production') {
assert(false, `invalid mode: ${mode}`)
}
}
}
init (app: any /* Vue component instance */) {
react router6
const history = this.history
// 根据history的类别执⾏相应的初始化操作和监听
if (history instanceof HTML5History) {
} else if (history instanceof HashHistory) {
const setupHashListener = () => {
history.setupListeners()
}
setupHashListener,
setupHashListener
)
}
history.listen(route => {
this.apps.forEach((app) => {
app._route = route
})
})
}
// VueRouter类暴露的以下⽅法实际是调⽤具体history对象的⽅法
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
this.history.push(location, onComplete, onAbort)
}
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
place(location, onComplete, onAbort)
}
}
  从上⾯可以看出:
  * 作为参数传递进⼊的字符串属性mode 只是⼀个标记,⽤来指⽰实际作⽤的对象属性history 的实现类,两者对应的关系如下:mode history的实现类
history HTML5History
hash HashHistory
abstract AbstractHistory
  * 在初始化对应的history 之前,会对mode 做⼀些判断:如果浏览器不⽀持HTML5History⽅式(通过 supportsPushState 来检测),则 mode 模式就强制设置为Hash模式,如果当前不是在浏览器中执⾏,就 mode 模式就强制设置为abstract模式。
  * VueRouter 类中共的 onReady(),push(),⽅法只是⼀个代理,它真正的实现是具体 History 对象的应⽤⽅法,在 init() ⽅法中初始化的时候,就根据 history 对象
具体的实现类来执⾏不同的操作。
  在浏览器环境下的两种模式,分别是在 HTML5History , HashHistory 两个类中实现的。
History模式实现的路由
  History interface是浏览器历史记录栈提供的接⼝,通过back(),forword(),go()等⽅法我们可以读取浏览器历史记录栈的信息,进⾏个各种跳转操作。
 在Html5开始, History interface提供了两个新的⽅法:pushState(),replaceState()是的我们可以对浏览器的历史记录栈进⾏修改
 window.history.pushState(stateObject,title,url)
 placeState(stateObject,title,Url)
  * stateObject:当浏览器跳转到新的状态的时候,将触发popState 事件,这个事件将携带这个 stateObject  参数的副本.
  * title: 所添记录的标题
  * URL: 所添记录的URL
  这两个⽅法都有⼀个共同的特点就是,当他们修改了浏览器的历史记录栈后,虽然当前的URL 改变了,
但是不会⽴即发送请求该 URL 的资源,这就为单页⾯应⽤前端路由“更新视图当不重新请求页⾯”提供了基础。
Hash模式实现的路由
  这种模式实现的路由,在通过链接后⾯添加 “#”+路由名字。
  hash 虽然是出现在 url 中,但是它不会被包含在 HTTP 请求⾥⾯。它是⽤来指⽰浏览器的动作的,对服务端完全是没有作⽤的,因此,改变 hash 是不会重新加载页⾯的。
  可以给hash的改变添加监听事件:
  window.addEventLIstener("hashchange",funcRef,false);
  每⼀次改变hash ,就会在浏览器的访问历史记录中添加⼀个记录。
  利⽤Hash 的以上特点可以实现前端路由的“更新视图但是不重新加载请求页⾯”的功能了。
两种模式的⽐较
  在⼀般的需求场景中,hash模式和history 模式是差不多的,但是它们之间的区别主要如下:
  * pushState 设置的新 URL 可以是与当前 URL 同源的任意 URL; ⽽修改 hash 只能修改 # 符号之后的部分;
  * pushState 设置的新的 URL 可以与当前的 URL ⼀摸⼀样,这样也会把记录添加到栈中,⽽ hash 设置的新值必须与原来的不⼀样才会被添加到栈中;
  * pushState 通过 stateObject 可以添加任何的数据到记录中;⽽ hash 只可以添加短字符串;
  * pushState 可以额外设置 title 属性后供后续使⽤;
History 模式的⼀个问题:
  我们知道对于单页⾯的应⽤来说,理想的使⽤场景是仅仅在进⼊应⽤的时候加载index.html,后续在的⽹络操作通过AJAX 完成,不会根据当前的URL 重新请求数据,但是难免会遇到特殊情况,如⽤户直接在地址栏中输⼊并回车,浏览器重启加载应⽤程序等。
  hash 模式只会改变hash 部分的内容,并且hash部分的内容是不会包含在Http 请求⾥⾯的,
oursite/#/user/id  //只会发送 oursite/
  在 Hash 模式下根据 url 请求页⾯时不会出现什么问题的,但是如果使⽤的是History 模式的,则会将 URL 修改得就和正常请求后端的URL ⼀样。
  在次情况下向后端发送请求的话,如果后端没有配置对应的/user/id 的路由处理,就会返会404错误。
  如果⼀定要使⽤ History 模式的话,为了防⽌页⾯刷新出现404情况,可以使⽤官⽅提供的解决⽅法是在服务端增加⼀个覆盖所有情况的候选资源:如果 URL 匹配不到任何的静态资源,则返回⼀个同⼀个 html.index 页⾯,这个页⾯就是你应⽤依赖的页⾯,但是这么做之后,服务器就不会返回404错误,因为这个时候,所有的页⾯都会返回 index 页⾯,为了避免这种情况,在 Vue 应⽤⾥⾯覆盖了所有的路由之后,然后再给出⼀个404页⾯。