The implementation method here is roughly the same as the source code, but the structure is different from the source code. For example, the source code of the matching route method is in the History class. I mostly put it in the VueRouter class because I forgot to look at the structure when I wrote it. There are also some re methods that are not as well handled as the source code (source code that I really do not understand, can only use their own understanding to write, the same history mode, I have not fully written) warehouse address

Where is the hook function executed

When VueRouter initializes the routes, it adds more information to the routes (route has no parent attribute and no path regular match). Create a Record object that contains this information

  1. The following four steps are completed after initialization, and the second step is to listen for the hashChange, Load, and popState events
    1. Create a record corresponding to route
    2. Add all existing paths to the pathList array
    3. Create a mapping table nameMap with route.name and the corresponding record
    4. Create a mapping table pathMap with route.path and the corresponding record
  2. Router. push is triggered when window.location changes or when the user clicks router-link
  3. The router. The push method call transitionTo, transitionTo method
    1. The currentRoute object 1 is created by using the match function to get the record that matches the current location. The currentRoute’s matched is an array in which (parent first) the routes that match the location and their parent routes are arranged in order
    2. Assign the current toRoute to fromRoute (the old route object) and currentRoute to toRoute
    3. Provides onComplete/onAbort methods that need to be executed when ConfirmTransitionTo completes/fails
  4. The ConfirmTransitionTo method does the following and then calls the onComplete/onAbort method of the appeal
    1. First, compare toRoute and fromRoute matched. If the order and address are the same, it indicates that the component in this route does not need to be re-rendered
let maxLength = Math.max(this.fromRoute.matched.length,this.toRoute.matched.length) var i for(i =0; i<maxLength; I ++){if I =1, toRoute/fromRoute's parent is reusable, If (this.fromroute. Matched [I]! ==this.toRoute.matched[i]){ break } } let activatedRoutes = this.toRoute.matched&&this.toRoute.matched.slice(i) // let activatedRoutes = this.fromRoute.matched&&this.fromRoute.matched.slice(i) let updatedRoutes = this.toRoute.matched&&this.toRoute.matched.slice(0,i)Copy the code

Now that we’ve got activatedRoutes, activatedRoutes, and updatedRoutes, we’re ready to get to the point

Implement methods in the routing hook function

BeforeRouterEnter; beforeResolve; afterEach hook; beforeRouterEnter; Cb // runQueue(queue,iterator, cb) // cb links the beforeRouterEnter and beforeResolve hook functions into arrays, // Call the transition onComplete method. Let queue = []. Concat ([]. Let queue = []. ... extractLeaveRoutesFn (transitionRoutes. DeviatedRoutes), / / call to leave the guards in the inactivation of components ... extractUpdateRoutesFn (transitionRoutes. UpdatedRoutes),... this. BeforeHooks, / / / calls global beforeEach guard, ...transitionRoutes.activatedRoutes.map(activatedRoute=>activatedRoute.beforeEnter) Filter (fn = > fn), / / call routing component inside beforeEnter resolveAsyncComponents (transitionRoutes. ActivatedRoutes) / / parsing asynchronous components]) runQueue(queue,iterator, () = > {/ / the above hook performed var queue = extractEnterGuards (transitionRoutes activatedRoutes, cb). The concat (enclosing resolveHooks) runQueue(queue,iterator, ()=> { this.pending = null; onComplete(this.toRoute); })})Copy the code
Global TV beforeEach, afterEach, beforeResolve

The general call is as follows

router.beforeEach((to, from, next) => {
    //do somthing
    next()
})
router.beforeResolve((to, from, next) => {
    //do somthing
    next()
})
router.afterEach((to, from, next) => {
    //do somthing
})

Copy the code

These three methods are defined on the prototype of VueRouter’s class, while the beforeHooks, resolveHooks, afterHooks arrays are defined on VueRouter’s constructor

/ / add fn registerHooks method to the corresponding array VueRouter inside. The prototype. BeforeEach = function (fn) {registerHooks (enclosing beforeHooks, fn)} VueRouter.prototype.beforeResolve = function(fn){ registerHooks(this.resolveHooks,fn) } VueRouter.prototype.afterEach = function(fn){ registerHooks(this.afterHooks,fn) }Copy the code
Route exclusive guard

The following beforeEnter is a property in the route, which means there is a beforeEnter method on the corresponding record,

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
Copy the code
A navigation hook within a component
const Foo = { template: `... `, beforeRouteEnter (to, from, next) { }, beforeRouteUpdate (to, from, next) { }, beforeRouteLeave (to, from, next) { }Copy the code

Handling navigation hooks within components is special

  1. Let’s start with beforeRouteLeave (extractUpdateRoutesFn is the same thing, but it’s just a multiplexed route called updatedRoutes)
extractLeaveRoutesFn(transitionRoutes.deviatedRoutes) function extractLeaveRoutesFn(deviatedRoutes) { Var FNS = [] deviatedRoutes&&deviatedRoutes. ForEach (deviatedRoute=>{ The component object has a navigation hook (if set) within the component. Let Components = deviatedRoute.components for(let [index,item] of Object.entries(components)){ if(typeof item ! VueComponent let def = vue.extend (item); // If component is not function, VueComponent lets def = vue.extend (item); // Get the instance object in this route, The registerInstance in vue.mixin defines let Instance = deviatedroute. instances[index] // get the beforeRouteLeave function of the VueComponent class Var f = def.options['beforeRouteLeave'] if(f){return FNS. Push (f.ind (instance))}}}}) return FNS}Copy the code
  1. ExtractEnterGuards extracts the beforeRouteEnter method within the component
extractEnterGuards(transitionRoutes.activatedRoutes,cb) var cbs = [] function extractEnterGuards(activatedRoutes, postEnterCbs) { var fns = [] activatedRoutes&&activatedRoutes.forEach(activatedRoute=>{ let components = activatedRoute.components for(let [index,item] of Object.entries(components)){ if(typeof item ! =='function'){ let def = Vue.extend(item); let instance = deviatedRoute.instances[index] var f = def.options['beforeRouteEnter'] if(f){ var f1 = Function (to,from,next){f(to,from,function (cb) { If (typeof cb === "function"){cbs.push(cb)}}) next()} FNS. Push (f1)}}}}) return FNS} if(typeof cb === "function"){cbs.push(cb)}) next()} FNS.Copy the code