0.前端路由原理
1.history模式原理:
利用history.pushState这个api,将路径推进栈中,页面不会刷新,网址会发生改变。然后window监听load和popstate事件,根据location.pathname的值,来替换router-view的内容。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
</head>
<body>
<a href="/home">主页</a>
<a href="/about">关于</a>
<div class="router-view"></div>
<script src="./history.js"></script>
</body>
</html>
const router_view = document.querySelector('.router-view');
const a_list = document.querySelectorAll('a');
for (let i = 0; i < a_list.length; i++) {
a_list[i].onclick = (e) => {
e.preventDefault();
const href = e.target.getAttribute('href') || '/';
history.pushState({}, null, path);
routerChange(href);
};
}
window.addEventListener('load', () => {
routerChange(location.pathname);
});
window.addEventListener('popstate', () => {
routerChange(location.pathname);
});
function routerChange(path) {
switch (path) {
case '/home':
router_view.innerHTML = 'Home';
break;
case '/about':
router_view.innerHTML = 'About';
break;
default:
router_view.innerHTML = '';
break;
}
}
2.hash路由原理:
浏览器改变网址后面的#/xxx部分是不会刷新页面的,我们就可以通过监听hashchange事件,从而变更router-view里面的内容。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
</head>
<body>
<a href="#/home">主页</a>
<a href="#/about">关于</a>
<div class="router-view"></div>
<script src="./hash.js"></script>
</body>
</html>
const router_view = document.querySelector('.router-view');
window.addEventListener('load', () => {
routerChange(location.hash.slice(1));
});
window.addEventListener('hashchange', () => {
routerChange(location.hash.slice(1));
});
function routerChange(path) {
switch (path) {
case '/home':
router_view.innerHTML = 'Home';
break;
case '/about':
router_view.innerHTML = 'About';
break;
default:
router_view.innerHTML = '';
break;
}
}
1.解析vue-router
vue-router的基本使用:
import Vue from 'vue';
import VueRouter from '../extends/my-router';
import Home from '../views/Home.vue';
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'Home',
component: Home,
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ '../views/About.vue'),
},
];
const router = new VueRouter({
mode: 'hash',
routes,
});
export default router;
- Vue.use(VueRouter):表示VueRouter是一个插件,它是一个方法或者VueRouter.install是一个方法
- new VueRouter(): 表示VueRouter是一个构造函数,所以它具有VueRouter.install这个一个方法。
2.重写vue-router
class HistoryRoute {
constructor() {
this.current = null;
}
}
class VueRouter {
constructor(options) {
this.mode = options.mode || 'hash';
this.routes = options.routes || [];
this.routeMap = this.createMap(this.routes);
this.history = new HistoryRoute();
this.init();
}
init() {
if (this.mode === 'history') {
window.addEventListener('popstate', () => {
this.history.current = location.pathname ? location.pathname : '/';
});
window.addEventListener('load', () => {
this.history.current = location.pathname ? location.pathname : '/';
});
} else {
window.addEventListener('hashchange', () => {
this.history.current = location.hash ? location.hash.slice(1) : '/';
});
window.addEventListener('load', () => {
this.history.current = location.hash ? location.hash.slice(1) : '/';
});
}
}
createMap(routes) {
const routeMap = {};
routes.forEach((route) => {
routeMap[route.path] = route.component;
});
return routeMap;
}
}
VueRouter.install = function(Vue) {
Vue.mixin({
beforeCreate() {
if (this.$options && this.$options.router) { // 跟组件组件
this._root = this;
this._router = this.$options.router;
// 我们需要将this._router.history变成响应式的,这样才能动态改变组件
Vue.util.defineReactive(this, 'xxx', this._router.history);
} else { // 子组件
this._root = this.$parent && this.$parent._root;
}
// 在每一个组件实例上添加$router
Object.defineProperty(this, '$router', {
get: () => {
return this._root._router;
},
});
// 在每个组件实例上添加$route
Object.defineProperty(this, '$route', {
get: () => {
return this._root_router.history.current;
},
});
// 注册router-link组件
Vue.component('router-link', {
props: {
to: String,
},
render(h) {
return h('a', { attrs: { href: this.to } }, this.$slots.default);
},
});
// 注册router-view组件
Vue.component('router-view', {
render(h) {
console.log(this.$router);
console.log(this.$router.history.current);
return h(this.$router.routeMap[this.$router.history.current]);
},
});
},
});
};
export default VueRouter;