vue-router学习

什么是前端路由?

在 Web 前端单页应用 SPA(Single Page Application)中,路由描述的是 URL 与 UI 之间的映射关系,这种映射是单向的,即 URL 变化引起 UI 更新(无需刷新页面)

如何实现前端路由?

要实现前端路由,需要解决两个核心:

  • 拿到当前需要展示的路由(监听url变化)
  • 根据路由渲染界面

实现一个简单的路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
let Vue = null;

class HistoryRoute {
constructor() {
this.current = null;
}
}
// 路由类
class VueRouter {
// 构造函数
constructor(options) {
this.mode = options.mode || "hash";
// 记录所有的路由
this.routes = options.routes || []; //你传递的这个路由是一个数组表
// 转为字典存起来 方便取数据
this.routesMap = this.createMap(this.routes);
// 记录当前路由类
this.history = new HistoryRoute();
// 监听路由变化 记录当前路由
this.init();
}
init() {
if (this.mode === "hash") {
// 先判断用户打开时有没有hash值,没有的话跳转到#/
location.hash ? "" : (location.hash = "/");
window.addEventListener("load", () => {
this.history.current = location.hash.slice(1);
});
window.addEventListener("hashchange", () => {
this.history.current = location.hash.slice(1);
});
} else {
location.pathname ? "" : (location.pathname = "/");
window.addEventListener("load", () => {
this.history.current = location.pathname;
});
window.addEventListener("popstate", () => {
this.history.current = location.pathname;
});
}
}
createMap(routes) {
return routes.reduce((pre, current) => {
pre[current.path] = current.component;
return pre;
}, {});
}
}

VueRouter.install = function (v) {
Vue = v;
// 父beforeCreate-> 父created -> 父beforeMounte -> 子beforeCreate ->子create ->子beforeMount ->子 mounted -> 父mounted
Vue.mixin({
beforeCreate() {
if (this.$options && this.$options.router) {
// 如果是根组件
this._root = this; //把当前实例挂载到_root上
this._router = this.$options.router;
// 监听history变化 更新ui
Vue.util.defineReactive(this, "xxx", this._router.history);
} else {
//如果是子组件
this._root = this.$parent && this.$parent._root;
}
Object.defineProperty(this, "$router", {
get() {
return this._root._router;
},
});
Object.defineProperty(this, "$route", {
get() {
return this._root._router.history.current;
},
});
},
});


Vue.component("router-link", {
props: {
to: String,
},
render(h) {
let mode = this._self._root._router.mode;
let to = mode === "hash" ? "#" + this.to : this.to;
return h("a", { attrs: { href: to } }, this.$slots.default);
},
});
Vue.component("router-view", {
render(h) {
let current = this._self._root._router.history.current;
let routeMap = this._self._root._router.routesMap;
return h(routeMap[current]);
},
});
};
export default VueRouter;