2021-01-02 Vue-router插件简单原理实现
Vue-router官方介绍
Vue-Router是Vue.js官方的路由管理器
安装:vue add router
使用步骤:
-
使用vue-router插件,router.js
import Router from 'vue-router' Vue.use(Router)
-
创建Router实例,router.js
export default new Router({...})
-
在根组件上添加该实例,main.js
import router from './router' new Vue({ router, }).$mount('#app')
-
添加路由视图,导航,App.vue
<router-view></router-view> <router-link to="/">Home</> this.$router.push('/')
Vue-router源码实现
问题分析:
单页面应用程序中,url发生变化时,不能刷新页面,不能调后段接口,做的是前端路由,所以采用hash和history api两种前端路由模式
根据url显示对应的内容router-view是一个全局组件,数据也要是响应式的,current变量持有url地址一旦发生变化,动态执行render函数
实现一个插件:
一:实现一个VueRouter类
- 处理路由选项
- 监听url变化,hashchange
- 响应这个变化
二:实现install方法
- $router注册
- 两个全局组件
思考三个问题:
1、router是个插件,做了什么事
2、在根实例,挂载了一下router,为什么
3、router-view router-link为啥可以直接用
/**
* 自己的路由器
* 1、VueRouter类,是一个插件
*/
let Vue; // 引用构造函数,VueRouter中要使用
class VueRouter {
constructor(options) {
this.$options = options;
// 提前缓存path和route映射关系
this.routeMap = {};
this.$options.routes.forEach(route => {
this.routeMap[route.path] = route;
});
// 声明一个响应式的current
// 渲染函数如果要重复执行,必须依赖于响应式数据
const initial = window.location.hash.slice(1) || "/";
Vue.util.defineReactive(this, "current", initial);
// 监听url变化
window.addEventListener("hashchange", () => {
this.current = window.location.hash.slice(1);
// console.log(this.current);
});
}
}
// 插件要实现install方法
// 参数1就是Vue
VueRouter.install = function(_Vue) {
// 保存构造函数的引用
Vue = _Vue;
// console.log(this);
// 2、挂载$router到Vue原型
// 利用全局混入,延迟执行下面的代码,这样可以获取router实例,就是new Vue({router参数})
Vue.mixin({
beforeCreate() {
// this指向组件实例
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
}
});
// 3、声明两个全局组件router-view,router-link
// <router-link to="/abc"></router-link>
Vue.component("router-link", {
props: {
to: {
type: String,
required: true
}
},
render(h) {
// <a href="#/abc">xxx</a>
// this指向当前组件实例
return h("a", { attrs: { href: "#" + this.to } }, this.$slots.default);
}
});
Vue.component("router-view", {
render(h) {
// current
// 动态获取对应组件
/* let component = null;
const route = this.$router.$options.routes.find(
route => route.path === this.$router.current
);
if (route) component = route.component; */
const { routeMap, current } = this.$router;
const component = routeMap[current] ? routeMap[current].component : null;
return h(component);
}
});
};
export default VueRouter;
关于嵌套路由,后面补充…