主要知识点
- Hash与History
- 路由原理
- 实现路由
一个vue路由的工作流程
- 前端路由
- 输入url---js解析地址---找到对应页面的地址---执行页面生成的js---看到页面
- 后端路由
- 输入url---请求发送到服务器---服务器解析请求的路径---拿到对应的页面---返回出去
- 流程图
Hash与History的使用
- hash
- #号后的就是hash的内容
- 可以通过location.hash拿到
- 可以通过onhashchange监听hash的改变
- history
- history即正常的路径
- location.pathname
- 可以用onpopstate监听history变化
源码解析
注册vue插件的时候,用到的api
import Router from 'vue-router'
Vue.use(Router)
最终执行的是插件的install方法
install
该方法主要做了以下几件事:
- 判断该插件是否安装过,如果未安装才安装;
- 缓存全局的vue变量,避免需要额外的import;
- 在所有component中混入钩子函数beforeCreate和destory,并且在钩子函数中注册实例;
- 拦截$router,取值时指向vm._routerRoot._router;
- 拦截$route,取值时指向vm._routerRoot._route;
- 注册全局组件routerView和routerLink;
- 路由的钩子函数采用和组件的钩子函数created一样的合并策略;
实现一个基础vue-router
- 要点
- 实现install方法,installl:function(Vue);
- 要全局混入Vue实例,用Vue.mixin;
- Vue.util.defineReactive的使用,该方法是对data的监听,vue的data监听用的就是这个方法;可以利用该方法监听current的变化;
class HistoryRouter {
constructor() {
this.current = null;
}
}
class VueRouter {
constructor(options) {
this.mode = options.mode || 'hash';
this.routes = options.routes || [];
this.history = new HistoryRouter();
this.routesMap = this.createMap(this.routes);
this.init();
}
init() {
this.listenUrlChange(this.mode);
}
listenUrlChange(mode) {
location.hash ? "" : location.hash = '/';
window.addEventListener('load', () => {
this.history.current = location.hash.slice(1);
});
var eventName = mode === 'hash' ? 'hashchange' : 'popstate';
window.addEventListener(eventName, () => {
this.history.current = location.hash.slice(1);
});
}
createMap(routes) {
return routes.reduce((memo, current) => {
memo[current.path] = memo[current.component];
return memo;
}, {});
}
}
VueRouter.install = function(Vue) {
Vue.mixin({
beforeCreate() {
if (this.$options && this.$options.router) {
this._root = this;
this._router = this.$options.router;
Vue.util.defineReactive(this, 'currrent', this._router.history);
} else {
if (this.$parent) {
this._root = this.$parent._root;
}
}
Object.defineProperty(this, '$router', {
get() {
return this._root._router;
}
//不写set,是因为外部不能修改this.$router的值
});
}
});
//注册全局组件
Vue.component('router-view', {
render(h) {
let current = this._self._root._router.history.current;
let routesMap = this._self._root._router.routesMap;
let component = routesMap[current];
//拿到组件,将组件渲染出来
h(component);
}
});
}
export default VueRouter;