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

【vue-router源码】一、router.install分析

时间:2023-03-31 16:24:46 vue.js

前言【vue-router源码】系列文章将带你从0开始了解vue-router的具体实现。本系列文章源码参考vue-routerv4.0.15。源码地址:https://github.com/vuejs/router阅读本文的前提是你最好了解vue-router的基本使用。如果没有使用过,可以通过vue-router官网进行学习。本文首先介绍router.install过程。vue-router的使用在介绍router.install之前,先看看vue3中vue-router的使用方法。import{createApp}from'vue'import{createRouter}from'vue-router'constrouter=createRouter({...})constapp=createApp({})app.use(router).mount('#app')app.use执行过程中,会执行router.install,传入app实例。那么router.install过程中发生了什么?接下来我们一探究竟。router.installrouter.install源码位于createRouter,文件位置为src/router.ts。安装(app:App){constrouter=thisapp.component('RouterLink',RouterLink)app.component('RouterView',RouterView)app.config.globalProperties.$router=routerObject.defineProperty(app.config.globalProperties,'$route',{enumerable:true,get:()=>unref(currentRoute),})if(isBrowser&&!started&¤tRoute.value===START_LOCATION_NORMALIZED){started=truepush(routerHistory.location).catch(err=>{if(__DEV__)warn('启动路由器时出现意外错误:',err)})}constreactiveRoute={}as{[kinkeyofRouteLocationNormalizedLoaded]:ComputedRef}for(START_LOCATION_NORMALIZED中的常量键){reactiveRoute[key]=computed(()=>currentRoute.value[key])}app.provide(routerKey,router)app.provide(routeLocationKey,reactive(reactiveRoute))app.provide(routerViewLocationKey,currentRoute)constunmountApp=app.unmountinstalledApps.add(app)app.unmount=function(){installedApps.delete(app)if(installedApps.size<1){pendingLocation=START_LOCATION_NORMALIZEDremoveHistoryListener&&removeHistoryListener()removeHistoryListener=currvalueListenerRonull=uteSTART_LOCATION_NORMALIZED复制代码started=falseready=false}unmountApp()}if((__DEV__||__FEATURE_PROD_DEVTOOLS__)&&isBrowser){addDevtools(app,router,matcher)}}在安装中,两个主要组件,RouterLink和RouterView,将首先注册应用程序。component('RouterLink',RouterLink)app.component('RouterView',RouterView)然后会将当前路由器对象分配给app.config.globalProperties.$router;同时拦截app.config.globalProperties.$route的get操作,让app.config.globalProperties.$route一直获取unref(currentRoute),unref(currentRoute)是当前路由的一些信息,我们不去深究放到这里,在后面的章节中会详细介绍。这样就可以通过组件中的this.$router获取router,通过this.$route获取当前的路由信息??。app.config.globalProperties.$router=routerObject.defineProperty(app.config.globalProperties,'$route',{enumerable:true,get:()=>unref(currentRoute),})后跟浏览器url地址进行第一次跳转(如果是浏览器环境)。if(isBrowser&&//用于初始导航客户端,以避免在多个应用程序中使用路由器时多次推送!started&¤tRoute.value===START_LOCATION_NORMALIZED){started=truepush(routerHistory.location).catch(err=>{if(__DEV__)warn('Unexpectederrorwhenstartingtherouter:',err)})}然后声明一个reactiveRoute响应对象,并遍历START_LOCATION_NORMALIZED对象,将START_LOCATION_NORMALIZED中的key依次复制到reactiveRoute中,同时,reactiveRoute中key对应的值变成了一个计算属性。这里START_LOCATION_NORMALIZED是vue-router提供的初始路由位置。通过START_LOCATION_NORMALIZED构建一个响应式路由reactiveRoute,方便跟踪路由变化。constreactiveRoute={}as{[kinkeyofRouteLocationNormalizedLoaded]:ComputedRef}for(constkeyinSTART_LOCATION_NORMALIZED){reactiveRoute[key]=computed(()=>currentRoute.value[key])}app.provide(routerKey,router)app.provide(routeLocationKey,reactive(reactiveRoute))app.provide(routerViewLocationKey,currentRoute)这里使用provide将router和currentRoute注入app实例。你可能会想,在前面的过程中,你可以在组件中使用this.$router和this.$route来获取相应的数据。这里为什么又要用provide注入呢?这是因为在设置模式下无法访问它。这时候通过inject就可以轻松获取到router和currentRoute。最后会把app放到一个哈希表中,然后重写app.unmount。卸载app时,先从hash表中删除app,然后判断hash表的大小是否小于1,小于1说明没有使用vue-router的实例,则有必要重置一些状态并删除一些监听。constunmountApp=app.unmountinstalledApps.add(app)app.unmount=function(){installedApps.delete(app)if(installedApps.size<1){pendingLocation=START_LOCATION_NORMALIZEDremoveHistory_Listener&&removeHistoryListener()removeHistoryListener()removeHistoryListener=Zarrvalue=null复制代码curutestarted=falseready=false}unmountApp()}总结通过以上分析,router.install主要做了以下几件事:注册RouterLink,RouterView组件设置全局属性$router,$route根据第一个路由跳转到app地址栏注入一些路由相关的信息,比如路由实例,响应式当前路由信息对象拦截app.unmount方法,卸载前重置一些属性删除一些监听函数