参考Vue-router, 实现一个简单的前端路由

思路

目前只实现了hash,整个思路是,咱们有一个主文件Router.js,这个文件中咱们定义了两大方法,use和routejavascript

use的做用是将全部的中间件全push到Router的middleware数组里面。route方法里面,咱们调用了this._matcher的addRoutes方法。this._matcher实际上是createMatcher的实例。html

route(path, controller){
        // 在执行controller以前, 先执行全部的中间件
        // 将全部routes及其controller添加进_matcher
        this._matcher.addRoutes(path, (req) => {
            this._middlewares.forEach(fn => {
                fn(req)
            });
            /** * res(response)实际是Router: this * callback(req, res) */
            console.log("传进来了......")
            controller&&controller(req, this)
        })
    }
复制代码

createMatcher的做用是将配置文件的全部路由规则正则,而且解析咱们每一次请求的url。它的match方法就是用于解析这个url。可是match方法是在HashHistory里面调用的。由于咱们的Router 实例化的时候,传给了它。并将实例化的赋值给this._history前端

this._history = this._mode === 'hash' 
            ? new HashHistory({matcher: this._matcher})
            : new Html5History({matcher: this._matcher});
复制代码

addRoutes接收一个path和一个handler,handler其实就是 路由配置文件里面的全部中间件,以及app.route(path, controller)里每一个路由对应的controller。path被正则化,用于咱们的app页面匹配每一个url,push到createMatcher的_routes里。vue

_toReg是将route(path, controller)的path正则化。java

addRoutes(path, handler){
        let routeReg = this._toReg({
            path: path,
            handler: handler,
            params: []
        });
        this._routes.push(routeReg);
    }
复制代码

咱们怎么样去截获一个请求呢?实际上用截获这个词,并不十分准确。在HashHistory里面,咱们经过_setListener,实现对hash变化的监听。git

_setListener(){
        window.addEventListener('load', this._refresh);
        window.addEventListener('hashchange', this._refresh);
    }
复制代码

当咱们要从页面a到达页面b的时候,是经过点击页面a上面的链接,这个连接有一个onclick事件,go里面的参数就是咱们的请求url。github

<li onclick="app.go('/order/fruit?price=100&time=now', {message: '订单'})">订单</li>
复制代码

当咱们点击它的时候,实际是咱们先修改window.location.hash这个值(点击事件先触发了go方法)。this._cache[url] = body,存储了咱们想要传入的信息。好比获取当前form表格的值。vue-router

go(url, body){
        this._cache[url] = body;
        console.log("come here........")
        window.location.hash = `${url}`;
    }
//..................................//
_getHash (){
        // 参考Vue-router
        // window.location.hash不稳定, Firefox会发布新版本
        const href = window.location.href;
        const index = href.indexOf('#');
        return index === -1 ? '' : href.slice(index + 1)
    }
复制代码

一旦hash被修改,咱们的onhashchange事件就能监听到,而后触发_refresh方法,_refresh里面调用_getHash,获取这个hash值,而后调用传参进来的createMatcher的match方法,解析这个path(实际就是上面提到的url);解析完以后返回一个matchedRoutes,这个matchedRoutes不只包含解析完的param,还包括这个route对应的handler(handler包括中间件和路由对应的controller)。数组

this._refresh = () => {
            // 每次hash变化, 获取变化后的hash
            console.log("refesh啦!............")
            const path = this._getHash();
            const matchedRoutes = this.matcher.match(path);
            this._matchedCount = matchedRoutes.length;
            this._fireHandlers(matchedRoutes, this._cache[path]);
        }
复制代码

_fireHandlers是最终call handler,而且处理请求的最终函数。app

_fireHandlers(matchedRoutes, body) {
        console.log("I am the best one")
        for (let i = 0; i < matchedRoutes.length; i++) {
            // 匹配到的路由包含有待执行的controller
            const item = matchedRoutes[i];
            // 构造请求体
            const request = {
                body: body || {},
                query: item.query,
                params: item.params
            };
            def(request, 'route', item.path);
            def(request, 'url', item.url);
            item.handler(request)
        }
    }
复制代码

参考

很是感谢sme-router做者!

从他的代码中, 学习到了不少, 对Vue-router的理解也加深了更多!

相关文章
相关标签/搜索