Vue router source code analysis (2) design idea and code structure

Time:2021-1-17

According to the execution process of vuerouter, we can understand its design idea through these three steps

  • Step 1: when we create an instance of new vuerouter, we will parse the array corresponding to the incoming router attribute through deep traversal, and save it in a map. Each map corresponds to an element of the router, which is called routing record. When parsing, we will add a regular expression to each routing record forComponent finds which routing record can match it at render time
  • Step 2: analysisComponents are first named props (for example, to)landThen it will traverse each record (routing record) in the first step map, and use the regularity in the routing record to match the to value to see if the regularity can match. If it can match, it means that the component corresponding to the routing record can be rendered. Then it will render a native DOM tag through the $createElement global function in Vue (the default is a tag, which can be rendered through theAfter rendering, a click event will be bound to the DOM object. When the click event is triggered, the push() method of the vuerouter instance will be called to modify the route. Note that the vuerouter triggers the route through the click event, not through the A’s attribute. If other events are passed in through the event props, the vuerouter will also be bound
  • The third step: renderingComponent, it first gets the currentThe number of layers nested relative to the depth of the topmost large Vue instance, and then this$ route.matched The (this. Net) contains the component information corresponding to all parent chain routes$ route.matched It is the routing record of all nested routing segments corresponding to the current routing record, that is, all parent routing objects are in this array, which contains the routing information of the current page This. $route object is a responsive data, which will change according to different pages. We will explain the difference between $route and $route separately later

There are three routing modes in vuerouter

  • Hash uses the URL hash value for routing
  • History relies on HTML5 history API and server configuration
  • abstractSupports all JavaScript runtime environments, such as Node.js Server side

Writer by: Desert QQ: 22969969

These three patterns have a lot in common, so vuerouter defines a history base class when implementing, defines common methods on the base class, and then defines three subclasses to inherit the whole history class for implementation, as follows:

class History {
    //Define some common methods, such as jump operations
}

class HashHistory extends History {
    //Different implementation of hash mode, such as getting hash value and setting hash value
}

class HTML5History extends History {
    //Different implementation of HTML5 mode, such as getting the current address and setting the current address
}

class AbstractHistory extends History {
    //The difference realization of abstract pattern
}

Vuerouter will create a corresponding instance of history according to the current pattern, and then perform a series of operations on the whole instance

Loading process of vuerouter

When vuerouter is loaded, it executes the Vue.use (vuerouter) is installed automatically as follows:

if (inBrowser &&  window.Vue ){// if in the browser environment and window.Vue existence
  window.Vue.use (vuerouter); // call window.Vue.use Install vuerouter, and the install method is executed
}

When the Vue plug-in is installed, the corresponding install method will be executed. The information related to loading is as follows:

How to install function install (Vue) {// Vue router
        /*Brief introduction*/
        Vue.mixin ({// mix in the lifecycle function. Note that the context within the function is a Vue instance
            Beforecreate: function beforecreate() {// beforecreate lifecycle function
                    if (isDef(this.$ options.router )){// if this$ options.router The router object passed in when the Vue instance is created
                        this._ Routerroot = this; // add a_ Routerroot points to itself, the Vue instance
                        this._ router = this.$ options.router ; // add a_ Router points to the instance of Vue router when constructing
                        this._ router.init (this); // Vue router instance calls init() to initialize, and the parameter is Vue instance
                        Vue.util.defineReactive (this, '_ route', this._ router.history.current ); // through Vue's definereactive_ Router becomes responsive, equal to this_ router.history.current
                    }Else {// non root component
                        this._ routerRoot = (this.$parent && this.$parent._ Routerroot) | this; // if this$ options.router Set $this_ Routerroot is the name of the placeholder node_ Routerroot, so you can access the Vue rooter instance
                    }
                    registerInstance(this, this);
                },
            Destroyed: function destroyed() {// destroy lifecycle function
                registerInstance(this);
            }
        });
        /*Brief introduction*/
        Vue.component ('routerview ', view); // register routerview component
        Vue.component ('routerlink ', link); // register routerlink
 
    }

We can see that we insert a piece of code into the beforecreate life cycle function of Vue through mixin, which will be passed through this$ options.router.init (this) execute the initialization code (this$ options.router This is the vuerouter instance that we passed in when we executed new vue(), This will execute vuerouter’s init () method, as well as the Vue.component The () method registers the routerview and routerlink components as global components.

The init method of vuerouter is to initialize the route. If there is no route on the current page (for example http://test.com/ )Is initialized to the root address / (e.g http://test.com/#/ ), which is the process of executing the transitionto method of the base class to jump. Specifically, you don’t paste the code. One paste will cause too much code.

Vuerouter’sExecution process

Let’s look at the previous article https://www.cnblogs.com/greatdesert/p/12398443.html For example, sort out the execution process of vuerouter in turn

The above is the loading process. For example, when we execute new vuerouter:

Const routes = [// define route points
        {path:'/login',component:login},
        {path:'/hello',name:'user',component:hello},
        {path:'/info/:id',component:info},
    ]

    Var router = new vuerouter ({// create a vuerouter instance)
        routes
    })

Will execute the constructor of Vue Router:

Var vuerouter = function vuerouter (options) {// constructor
  If (options = = void 0) options = {}; // if option is undefined, it will be fixed to an empty object

  this.app = null;
  this.apps = [];
  this.options = options;
  this.beforeHooks = [];
  this.resolveHooks = [];
  this.afterHooks = [];
  this.matcher  = createMatcher( options.routes  ||[], this); // converts the routing information into an object information and returns an object containing the match and addroutes attributes, corresponding to two functions respectively

  //Initialization / correction mode
  var mode =  options.mode  ||'hash'; // if there is no mode, the default is hash mode
  this.fallback  = mode === 'history' && !supportsPushState &&  options.fallback  ! = = false; // if the current mode is history, but the browser does not support pushstate, then fallback is not false, then set fallback to true
  if (this.fallback) {
    mode = 'hash';
  }
  if (!inBrowser) {
    mode = 'abstract';
  }
  this.mode = mode;

  Switch (mode) {// according to different modes, the this.history Make instantiation
    case 'history':
      this.history = new HTML5History(this, options.base);
      break
    case 'hash':
      this.history = new HashHistory(this, options.base, this.fallback);
      break
    case 'abstract':
      this.history = new AbstractHistory(this, options.base);
      break
    default:
      {
        assert(false, ("invalid mode: " + mode));
      }
  }
};

The creatematcher function will parse the router value we passed in. The logic of this function is as follows:

function createMatcher (routes,router) {    
  Var ref = createroutemap (routes); // create a map, which is the route record mentioned in the first step above
  var pathList = ref.pathList;
  var pathMap = ref.pathMap;
  var nameMap = ref.nameMap;

  function addRoutes (routes) {
    createRouteMap(routes, pathList, pathMap, nameMap);
  }

  function match (raw,currentRoute,redirectedFrom) {/**/}
  function redirect (record,location) { /**/ }

  function alias (record,location,matchAs) { /**/ }
  function _createRoute (record,location,redirectedFrom) { /**/ }

  Return {match: match, addroutes: addroutes} // returns this object. We can directly execute the functions corresponding to the two keys to match the routing records
}

For the example, the route record created here is as follows:

Namemap is used to name routes, pathlist is used to store all routes, and pathmap is the place to record all routes.

With routing records, the Vue link and Vue view components can make a big show. These two components will be explained separately later

Recommended Today

Use of Android WebView (super detailed usage)

1.1 overview of WebView Android WebView is a special view on the Android platform. It can be used to display web pages. This WebView class can be used to display only one online web page in the app. Of course, it can also be used to develop browsers. The internal implementation of WebView uses WebKit […]