首先vue-router是什么?
官网上的介绍是最准确的,如下图所示。
知道了是什么,接下来我们将在vue-router里众多的功能里挑出最核心的来手写实现下。
- [使用hash模式根据路由配置展示对应的组件]
我们还得先知道vue-router在vue项目中是怎么被使用的!
这里我使用vuecli工具新建一个vue2.x项目,并以插件的形式给项目添加vue-router,看看在vue里最基本的使用方式。
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
// 1.VueRouter是一个插件
Vue.use(VueRouter)
const routes = [{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () =>
import ( /* webpackChunkName: "about" */ '../views/About.vue')
}
]
// 2.创建实例
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
import router from './router'
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
1.第一步,引入vue-router,并作为参数传入Vue.use方法执行;这里可以看出 vue-router 是vue的一个插件,所以必须实现一个install的静态方法供Vue.use内部调用。那install方法里实现了什么功能呢?这里先按下不表,在后面的手写实现里,我再将答案抛出。
2.第二步,new VueRouter(options) 创建router实例,并传入一个选项对象,其中包含我们自定义的routes路由配置对象。
3.第三步,在new Vue的时候把router实例作为选项之一传入,这里传入router实例又是为了什么?
开始手写实现
// 保存Vue构造函数,插件中要使用,不导入就能用
let Vue;
// VueRouter类要求必须有一个install静态方法,将来会被Vue.use调用
class VueRouter {
constructor(options) {
// 保存new VueRouter 时传入的选项
this.$options = options;
// 使用defineReactive方法让current成为响应式数据,
// 后续被current依赖的router-view组件根据current变化而渲染对应的组件
// 将来发生变化,router-view的render函数能够再次执行
const hash = window.location.hash.slice(1) || "/";
Vue.util.defineReactive(this, 'current', hash)
// 监听hash变化
window.addEventListener("hashchange", () => {
this.current = window.location.hash.slice(1);
});
}
}
// 这将回答上面抛出的第一个问题:那install方法里实现了什么功能呢?
// 1.挂载$router属性
// 2.注册router-view,router-link组件
VueRouter.install = function(_Vue) { // 参数1会在Vue.use调用时传入
Vue = _Vue;
// 在这里通过mixin的方式延迟到组件的beforeCreate钩子处执行,这时候可访问vue的实例
Vue.mixin({
beforeCreate() {
// 这将回答上面抛出的第二个问题:在new Vue的时候把router实例作为选项之一传入,这里传入router实例又是为了什么?
// 因为需要把router实例挂载到Vue.prototype上,以后在Vue的任何组件里访问
if (!Vue.prototype.$router && this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
},
});
// 注册 router-link 组件,实际渲染的就是<a>标签
Vue.component("router-link", {
props: {
to: {
type: String,
required: true,
},
},
render(h) {
return h(
"a",
{
attrs: {
href: "#" + this.to,
},
},
this.$slots.default
);
},
});
// 注册 router-view 组件,根据用户自己配置的routes,与current相匹配找出对应的组件用h方法直接渲染
Vue.component("router-view", {
render(h) {
// 获取当前路由对应的组件
let component = null
const route = this.$router.$options.routes.find(
(route) => route.path === this.$router.current
);
if (route) {
component = route.component
}
return h(component);
},
});
};
export default VueRouter;