什么是前端路由?
在 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;
|