You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
我们通过vue Router传入routes的时候,会根据routes内部会维护一份路由的映射关系,pathList、pathMap、nameMap对象,key为path or name 值为record;record会最终当成参数传入的route对象的matched属性内,用于router-view内渲染对应组件
全局概览
这里会借助下面这张内部流程图,先有个大致印象,然后后面在逐个进行分析;vue-router 3.1.2
VueRouter实例化
在得到VueRouter实例对象的时候我们可以传入需要的routes参数,目的是得到一个路由映射关系对象,可以根据path or name快速找到route对应的record记录;也可以传入mode参数,选择路由方式
我们通过vue Router传入routes的时候,会根据routes内部会维护一份路由的映射关系,pathList、pathMap、nameMap对象,key为path or name 值为record;record会最终当成参数传入的route对象的matched属性内,用于router-view内渲染对应组件
Vue.mixin内给根组件设置_router属性与_route属性
通过直接在Vue.prototype上添加$router、$route属性,保证每个vue组件可以通过this.$router及this.$route属性访问路由router对象与route对象;然后将_route属性设置为响应式属性,保证_route属性变化的时候,视图能够更新
初始化跳转流程
init内通过history.transitionTo(history.getCurrentLocation())进行初始化跳转;transitionTo内会先通过this.router.match(location, this.current)返回匹配的route对象,而match方法内则是通过传入的location,然后在nameMap及pathMap内获取对应的匹配项;如果没有回到到则返回首页的route对象,但是route属性的matched属性值为空,最终渲染不出组件;
获取到route对象,之后调用confirmTransition,通过比对route与this.current是否相同,如果相同则abort取消跳转;不相同则调用成功回调,然后执行updateRoute(route)方法,更新this.current及调用this.cb;this.cb内最终会执行app._route = route赋值操作,触发响应式更新
router.push or router.replace内部执行流程
VueRouter原型上的push、replace方法,内部是调用this.history.push、this.history.replace方法,而this.history.push、this.history.replace方法内部最终确认跳转之后,使用的又是window.history.pushState、window.history.replaceState api;如果不支持pushState api则使用location.replace、location.assign进行跳转
hash模式下,如果不支持pushState,则使用location.hash、location.replace来实现跳转;
并且我们可以从上面看到,HashHistory、HashHistory内的push、replace方法都是用的是this.transitionTo来进行确认跳转,跳转成功之后,会调用updateRoute,然后更新app._route = route,最终触发根组件的响应式更新
浏览器前进后退怎么触发视图更新
history模式下,因为popstate事件,无法监听pushState、replaceState触发的跳转;所以我们直接在HTML5History()构造函数初始化的时候,直接注册popstate事件监听函数;监听回调函数内又通过获取更新后的location,然后通过this.transitionTo来进行导航,最终更新_route属性,从而触发视图更新
hash 模式下,定义了setupListeners原型方法,该方法在init的时候会被调用;因为hashChange事件,能够监听到location.hash、location.replace触发的更新,所以没有在HashHistory构造函数执行的时候去过早的设置监听,而是init内的首次跳转成功or失败的回调内在去调用setupListeners设置监听;监听函数内又通过获取更新后的location,然后通过this.transitionTo来进行导航,最终更新_route属性,从而触发视图更新
通过popstate、hashchange事件监听url的变化,然后在监听函数内通过this.transitionTo来进行确认跳转,跳转成功之后,更新_route属性,达到视图更新
注意hash模式下,且浏览器不支持pushState方法,那么我们在通过push、replace方法去实现hash跳转成功的时候,必然会再次触发hashChange事件;那么是怎么做到避免触发第二次跳转的呢?原因就在confirmTransition方法内,对isSameRoute的判断,因为第二次跳转匹配到的route与this.current存的上次route值,是相同的,所以取消了第二次跳转
路由钩子的执行机制与顺序
全局路由钩子
路由独享的钩子
组件路由钩子
完整的导航解析流程
addRoutes动态添加路由规则
我们可以通过addRoutes向我们的应用动态添加路由规则,然后我们就可以动态匹配页面及组件
route-view渲染组件
RouterView作为一个函数式组件,即无状态 (没有响应式数据),也没有实例 (没有 this 上下文),第二个参数提供上下文;通过获取route.matched[depth]属性内的组件,最终调用 h(component, data, children)来渲染对应的ui组件
在看全局
在看这张图,是不是清楚了vue-router内部的运行机制了;简而言之vue-router;分为两个部分,第一部分history部分,第二个部分与vue结合部分
history部分提供统一的跳转方法及返回路由对象,允许设置导航成功回调函数、执行钩子函数
vue结合部分则是,通过传入导航监听函数,然后在监听函数内更新app._route,从而达到响应式更新的目的;还有则是对history api的一层封装及提供hooks的注册方法等
The text was updated successfully, but these errors were encountered: