执行过程: 当用户点击 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;
- });
- });
- };
在初始化对应的 history 之前, 会对 mode 做一些校验: 若浏览器不支持 HTML5History 方式 (通过 supportsPushState 变量判断), 则 mode 设为 hash; 若不是在浏览器环境下运行, 则 mode 设为 abstract;
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 页面.
来源: http://www.jianshu.com/p/2a0591da2be4