vue-router的三种模式解析面试官:请说说vue-router的两种模式...我:不会vue-router有三种模式吗?图案???一、前言vue-router有几种模式?根据vue-router官网,我们可以清楚的看到vue-router的mode值有3种hashhistoryabstract,其中hash和history是SPA单页应用的基础。先说结论:spa应用路由有2种模式,hash和history,vue路由有3种模式,比spa抽象了一种。2、源码分析在vue-router中,通过mode参数修改路由模式:constrouter=newVueRouter({mode:'history',routes:[...]})如何实现,首先我们下载vue-提取router源码处理modeclassvueRouter{constructor(options){letmode=options.mode||'hash'this.fallback=mode==='history'&&!supportsPushState&&options.fallback!==falseif(this.fallback){mode='hash'}if(!inBrowser){mode='abstract'}this.mode=模式切换(模式){case'history':this.history=newHTML5History(this,options.base)breakcase'hash':this.history=newHashHistory(this,options.base,this.fallback)breakcase'abstract':this.history=newAbstractHistory(this,options.base)breakdefault:if(process.env.NODE_ENV!=='production'){assert(false,`invalidmode:${mode}`)}}}}可以看到默认使用的是hash模式。当设置为history时,如果不支持history方法,在不在浏览器环境下也会强制使用hash模式,比如node,直接强制使用abstract模式。在以hash方式阅读这部分源码之前,我们先来了解一下hash的基础知识:根据MDN上的介绍,Location接口的hash属性返回一个USVString,其中会包含URL标识中的'#'和随后的URL片段标识符“#”和随后的URL片段标识符称为散列。它有一些特点:在第一个#之后出现的任何字符都将被浏览器解释为位置标识符。这意味着,这些字符都不会发送到服务器。只需更改#后面的部分,浏览器只会滚动到相应的位置,不会重新加载网页。每更改一次#后面的部分,浏览器的访问历史记录中就会添加一条记录,您可以使用“返回”按钮返回到之前的位置。通过window.location.hash属性可以读取hash值,window.location.hash属性是可读可写的。使用window.addEventListener("hashchange",fun)来监听哈希变化。了解了这些基础知识之后,我们继续看vue-router源码中对/src/history/hash.js的处理。常量handleRoutingEvent=()=>{constcurrent=this.currentif(!ensureSlash()){return}this.transitionTo(getHash(),route=>{if(supportsScroll){handleScroll(this.router,route,current,true)}if(!supportsPushState){replaceHash(route.fullPath)}})}consteventType=supportsPushState?'popstate':'hashchange'window.addEventListener(eventType,handleRoutingEvent)this.listeners.push(()=>{window.removeEventListener(eventType,handleRoutingEvent)})首先,使用window.addEventListener("hashchange",fun)来监听路由变化,然后使用transitionTo方法更新视图push(location:RawLocation,onComplete?:Function,onAbort?:Function){const{current:fromRoute}=thisthis.过渡到(位置,路线e=>{pushHash(route.fullPath)handleScroll(this.router,route,fromRoute,false)onComplete&&onComplete(route)},onAbort)}replace(location:RawLocation,onComplete?:Function,onAbort?:Function){const{current:fromRoute}=这个这个。transitionTo(location,route=>{replaceHash(route.fullPath)handleScroll(this.router,route,fromRoute,false)onComplete&&onComplete(route)},onAbort)}vue-router的两个主要APIpush和replace也简单处理哈希,然后调用transitionTo方法来更新视图。history模式的老规矩,先来了解一下HTML5History的基础知识:根据MDN上的介绍,History接口允许操作浏览器的history在tabs或frame中访问的Sessionhistory使用back(),forward(),和go()方法在用户的历史记录中来回跳转。HTML5引入了history.pushState()和history.replaceState()方法,分别用于添加和修改历史条目。了解history.pushState():window.onpopstate=function(e){alert(2);}letstateObj={foo:"bar",};history.pushState(stateObj,"page2","bar.html");这将使浏览器地址栏读取http://mozilla.org/bar.html,但不会导致浏览器加载bar.html,甚至不会检查bar.html是否存在。也就是说,虽然浏览器的URL发生变化,但不会立即向服务器重新发送请求,这也是spa应用更新视图而不重新请求页面的基础。然后我们继续看vue-router源码对/src/history/html5.js的处理:浏览器,但首先//自异步保护以来,历史路由未同时更新。constlocation=getLocation(this.base)if(this.current===START&&location===this._startLocation){return}this.transitionTo(location,route=>{if(supportsScroll){handleScroll(路由器,路由,current,true)}})}window.addEventListener('popstate',handleRoutingEvent)this.listeners.push(()=>{window.removeEventListener('popstate',handleRoutingEvent)})处理逻辑类似于hash,使用window.addEventListener("popstate",fun)监听路由变化,然后使用transitionTo方法更新视图。push、replace等方法不再详细介绍。抽象模式最后我们看一下/src/history/abstract.js的处理:constructor(router:Router,base:?string){super(router,base)this.stack=[]this.index=-1}首先定义2个变量,stack记录调用记录,index记录当前指针位置push(location:RawLocation,onComplete?:Function,onAbort?:Function){this.transitionTo(location,route=>{stack=this.stack.slice(0,this.index+1).concat(route)this.index++onComplete&&onComplete(route)},onAbort)}replace(location:RawLocation,onComplete?:Function,onAbort?:函数){this.transitionTo(location,route=>{this.stack=this.stack.slice(0,this.index).concat(route)onComplete&&onComplete(route)},onAbort)}push和replace方法也是通过stack和index这两个变量模拟浏览器的历史调用记录。3、总结最后,我们到了最后的总结阶段:hash和history的使用方法类似,hash中的route有#号,但是使用方便,不需要服务器配合。从技术角度来看,这是最容易配置的模式。我感觉这也是hash设置为默认模式的原因。history模式需要服务器配合404的情况,但是route中没有#,比hash漂亮。抽象模式不使用浏览器API,可以放在node环境或者桌面应用中。感觉是对spa应用的延伸和能力扩展。如有错误或不准确的地方,请务必指正,万分感谢。如果你喜欢或者有启发,欢迎在github上star,这也是对作者的一种鼓励。
