• demo
  • github

Train of thought

So far only hash has been implemented. The whole idea is that we have a main file, router.js, in which we define two methods, use and route

Use pushes all middleware into the Router’s middleware array. In the route method, we call the this._matcher addRoutes method. This._matcher is actually an instance of createMatcher.

route(path, controller){
        // Execute all middleware before executing controller
        // Add all routes and their controller to _matcher
        this._matcher.addRoutes(path, (req) => {
            this._middlewares.forEach(fn= > {
                fn(req)
            });
            Router: this * callback(req, res) */
            console.log("It's coming in......")
            controller&&controller(req, this)})}Copy the code

CreateMatcher’s job is to reorganize all the routing rules in the configuration file and parse the URLS we request every time. Its match method is used to parse this URL. But the match method is called inside HashHistory. Because our Router was passed to it when it was instantiated. And assign the instantiated value to this._history

this._history = this._mode === 'hash' 
            ? new HashHistory({matcher: this._matcher})
            : new Html5History({matcher: this._matcher});
Copy the code

AddRoutes receives a path and a handler, which is all middleware in the routing configuration file and the controller for each route in app.route(Path, Controller). Path is regularized to match every URL on our app page and pushed into createMatcher’s _routes.

_toReg regularizes the path of route(Path, controller).

addRoutes(path, handler){
        let routeReg = this._toReg({
            path: path,
            handler: handler,
            params: []});this._routes.push(routeReg);
    }
Copy the code

How do we intercept a request? Actually the word intercept is not quite accurate. In HashHistory, we use _setListener to listen for hash changes.

_setListener(){
        window.addEventListener('load'.this._refresh);
        window.addEventListener('hashchange'.this._refresh);
    }
Copy the code

When we go from page A to page B, we do so by clicking on the link above page A, which has an onclick event, and the parameter in go is our request URL.

<li onclick="app.go('/order/fruit? Price =100&time=now', {message: 'order '})">The order</li>
Copy the code

When we click on it, we actually change the window.location.hash value first (the click event triggers the go method first). This. _cache[URL] = body stores the information we want to pass in. For example, get the value of the current form.

go(url, body){
        this._cache[url] = body;
        console.log("come here........")
        window.location.hash = `${url}`;
    }
/ /... //
_getHash (){
        / / reference Vue - the router
        // window.location.hash is unstable and Firefox will release a new version
        const href = window.location.href;
        const index = href.indexOf(The '#');
        return index === - 1 ? ' ' : href.slice(index + 1)}Copy the code

Once the hash has been modified, our onHashchange event can listen in and trigger the _refresh method, which calls _getHash, gets the hash value, and then calls the Match method of createMatcher that was passed in. Parse the path(which is actually the URL mentioned above); When parsed, a matchedRoutes is returned. This matchedRoutes not only contains the param parsed, but also contains the handler for the route (the handler includes middleware and the controller for the route).

this._refresh = (a)= > {
            // Every time the hash changes, get the changed hash
            console.log("Refesh! ...")
            const path = this._getHash();
            const matchedRoutes = this.matcher.match(path);
            this._matchedCount = matchedRoutes.length;
            this._fireHandlers(matchedRoutes, this._cache[path]);
        }
Copy the code

_fireHandlers are the final call handler and the final function that handles the request.

_fireHandlers(matchedRoutes, body) {
        console.log("I am the best one")
        for (let i = 0; i < matchedRoutes.length; i++) {
            // The matched route contains controllers to be executed
            const item = matchedRoutes[i];
            // Construct the request body
            const request = {
                body: body || {},
                query: item.query,
                params: item.params
            };
            def(request, 'route', item.path);
            def(request, 'url', item.url);
            item.handler(request)
        }
    }
Copy the code

reference

Many thanks to sme-Router author!

From his code, I learned a lot and deepened my understanding of vue-Router.