当前位置: 首页 > Web前端 > vue.js

【vue-router源码】四、createRouter源码分析

时间:2023-03-31 18:37:01 vue.js

前言【vue-router源码】系列文章将带你从0开始了解vue-router的具体实现。本系列文章源码参考vue-routerv4.0.15。源码地址:https://github.com/vuejs/router阅读本文的前提是你最好了解vue-router的基本使用。如果没有使用过,可以通过vue-router官网进行学习。本文将带大家分析一下createRouter的实现。使用constrouterHistory=createWebHistory()exportconstrouter=createRouter({history:routerHistory,strict:true,routes:[{path:'/home',redirect:'/'},{path:'/',components:{default:Home,other:component},props:{default:to=>({waited:to.meta.waitedFor})},},{路径:'/nested',别名:'/anidado',组件:嵌套,名称:'嵌套',孩子:[{路径:'嵌套',别名:'a',名称:'NestedNested',组件:嵌套,孩子:[{名称:'NestedNestedNested',路径:'嵌套',组件:嵌套,},],},{路径:'other',别名:'otherAlias',组件:嵌套,名称:'NestedOther',},{路径:'also-as-absolute',别名:'/absolute',name:'绝对孩子',component:Nested,},],},],asyncscrollBehavior(to,from,savedPosition){awaitscrollWaiter.wait()if(savedPosition){returnsavedPosition}else{if(to.matched.every((record,i)=>from.matched[i]!==record))return{left:0,top:0}}returnfalse},})createRouter在分析createRouter之前,先看它的参数类型:exportinterface_PathParserOptions{//使用正则表达式时区分大小写,默认falsesensitive?:boolean//是否禁止尾部斜线,默认falsestrict?:boolean//正则表达式前要加^,默认truestart?:boolean//正则表达式format以$结尾,默认为trueend?:boolean}exporttypePathParserOptions=Pick<_PathParserOptions,'end'|'敏感'|'strict'>exportinterfaceRouterOptionsextendsPathParserOptions{history:RouterHistory//路由表routes:RouteRecordRaw[]//在页面之间导航时控制滚动行为可以返回一个Promise来延迟滚动。scrollBehavior?:RouterScrollBehavior//用于自定义如何解析查询parseQuery?:typeoforiginalParseQuery//用于自定义查询对象如何转换为字符串stringifyQuery?:typeoforiginalStringifyQuery//激活RouterLink的默认类linkActiveClass?:string//AccurateActivatethedefaultclassofRouterLinklinkExactActiveClass?:string}让我们看看createRouter做了什么。createRouter方法一共885行(包括空行)。乍一看,你可能会觉得这个方法很复杂。仔细观察的话,很大一部分代码其实都是在声明一些函数。我们可以暂时放下这些函数声明,看看剩下的。首先,将使用createRouterMatcher方法创建路由匹配器matcher,并从选项中提取parseQuery、stringifyQuery和history属性。如果选项中没有历史记录,则会抛出错误。constmatcher=createRouterMatcher(options.routes,options)constparseQuery=options.parseQuery||originalParseQueryconststringifyQuery=options.stringifyQuery||originalStringifyQueryconstrouterHistory=options.historyif(__DEV__&&!routerHistory)thrownewError('调用“createRouter()”时提供“history”选项:'+'https://next.router.vuejs.org/api/#history.')后面声明了一些全局守卫相关的变量,以及一些关于params的处理方法,其中全局守卫相关的变量是通过useCallbacks创建的,params相关的方法是通过applyToParams创建的。//全局pre-guard相关方法constbeforeGuards=useCallbacks>()//全局resolutionguard相关方法constbeforeResolveGuards=useCallbacks>()//全局post-hook方法constafterGuards=useCallbacks()//当前路由,浅响应对象constcurrentRoute=shallowRef(START_LOCATION_NORMALIZED)letpendingLocation:RouteLocation=START_LOCATION_NORMALIZED//如果浏览器环境设置了scrollBehavior,那么需要防止页面自动退出恢复页面位置//https://developer.mozilla.org/zh-CN/docs/Web/API/History/scrollRestorationif(isBrowser&&options.scrollBehavior&&'scrollRestoration'inhistory){history.scrollRestoration='manual'}//标准化params,转换字符串constnormalizeParams=applyToParams.bind(null,paramValue=>''+paramValue)//编码paramconstencodeParams=applyToParams.bind(null,encodeParam)//解码参数constdecodeParams:(params:RouteParams|未定义)=>RouteParams=applyToParams.bind(null,decode)关于useCallbacks的实现:在useCallbacks中声明一个handlers数组保存所有添加的方法,useCallbacks的返回值包括三个方法:add(添加一个handler,返回一个deletehandler函数),list(返回所有处理程序),reset(清除所有处理程序)exportfunctionuseCallbacks(){lethandlers:T[]=[]functionadd(handler:T):()=>void{handlers.push(handler)return()=>{consti=handlers.indexOf(处理程序)如果(i>-1)个处理程序。splice(i,1)}}functionreset(){handlers=[]}return{add,list:()=>handlers,reset,}}applyToParams的实现:接收一个handler函数和params对象,遍历params对象,并对每个属性值执行fn并将结果分配给一个新对象导出函数applyToParams(fn:(v:string|number|null|undefined)=>string,params:RouteParamsRaw|undefined):RouteParams{constnewParams:RouteParams={}for(constkeyinparams){constvalue=params[键]newParams[键]=Array.isArray(值)?value.map(fn):fn(value)}returnnewParams}并声明了大量的函数,包括addRoute、removeRoute、getRoutes等,这些函数都是我们日常使用的addRoute、removeRoute等。在createRouter的最后,创建并返回了一个router对象,里面几乎包含了声明的所有函数。综上所述,createRouter函数声明了一些变量和很多全局钩子需要的函数。这些函数就是我们日常使用的一些方法,比如addRoute、removeRoute等,在函数的最后声明了一个router对象。上面声明的大部分函数都会包含在这个对象中,最终会返回路由器。路由器中有一个重要的安装方法。安装过程可以看之前的文章,这里不再赘述。对于路由器中的每一个功能,都会在后续的文章中继续介绍。