vue-router 原理

执行过程:当用户点击 router-link 标签时,会去寻找它的 to 属性, 它的 to 属性和 js 中配置的路径{ path: '/home', component: Home} path 一一对应,从而找到了匹配的组件, 最后把组件渲染到 标签所在的地方。

vue-router 是 vue.js 框架的路由插件,它是通过 mode 这一参数控制路由的实现模式的。

const router = new VueRouter({
    // HTML5 history 模式
    mode: 'history',
    base: process.env.NODE_ENV === 'production' ? process.env.PROXY_PATH : '',
    routes,
})

源码分析

var VueRouter = function VueRouter (options) {
    if ( options === void 0 ) options = {};

    this.app = null;
    this.apps = [];
    this.options = options;
    this.beforeHooks = [];
    this.resolveHooks = [];
    this.afterHooks = [];
    // 创建 matcher 匹配函数
    this.matcher = createMatcher(options.routes || [], this);
    // 根据 mode 实例化具体的 History,默认为'hash'模式
    var mode = options.mode || 'hash';
    // 通过 supportsPushState 判断浏览器是否支持'history'模式
    // 如果设置的是'history'但是如果浏览器不支持的话,'history'模式会退回到'hash'模式
    // fallback 是当浏览器不支持 history.pushState 控制路由是否应该回退到 hash 模式。默认值为 true。
    this.fallback = mode === 'history' && !supportsPushState &&   options.fallback !== false;
    if (this.fallback) {
        mode = 'hash';
    }
    if (!inBrowser) {
        // 不在浏览器环境下运行需强制为'abstract'模式
        mode = 'abstract';
    }
    this.mode = mode;

    // 根据不同模式选择实例化对应的 History 类
    switch (mode) {
        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));
        }
    }
};

history 模式

VueRouter.prototype.init = function init (app /* Vue component instance */) {
    
    ...
    
    var history = this.history;

    // 根据history的类别执行相应的初始化操作和监听
    if (history instanceof HTML5History) {
        history.transitionTo(history.getCurrentLocation());
    } else if (history instanceof HashHistory) {
        var setupHashListener = function () {
            history.setupListeners();
        };
        history.transitionTo(
          history.getCurrentLocation(),
          setupHashListener,
          setupHashListener
        );
    }

    history.listen(function (route) {
        this$1.apps.forEach(function (app) {
            app._route = route;
        });
    });
};
  1. 在初始化对应的history之前,会对mode做一些校验:若浏览器不支持HTML5History方式(通过supportsPushState变量判断),则mode设为hash;若不是在浏览器环境下运行,则mode设为abstract;
  2. VueRouter类中的onReady(),push()等方法只是一个代理,实际是调用的具体history对象的对应方法,在init()方法中初始化时,也是根据history对象具体的类别执行不同操作

pushState和replaceState两种方法的共同特点:当调用他们修改浏览器历史栈后,虽然当前url改变了,但浏览器不会立即发送请求该url,这就为单页应用前端路由,更新视图但不重新请求页面提供了基础。

而history模式则将url修改的就和正常请求后端的url一样(history不带#)

http://oursite.com/user/id

如果这种向后端发送请求的话,后端没有配置对应/user/id的get路由处理,会返回404错误。

你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面

给个警告,因为这么做以后,你的服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件。为了避免这种情况,你应该在 Vue 应用里面覆盖所有的路由情况,然后在给出一个 404 页面。

你可能感兴趣的:(vue-router 原理)