前言
好奇 Vue 与 Vue-Router 是怎么形成关联,怎么去渲染的,就出现了这篇总结的文章。
在使用Vue-Router的过程中都要经过这几个步骤:
- Vue-Router 实例化
- Vue-Router 的实例通过 Vue.use 形式建立关系
- Vue-Router 的实例挂载到 Vue 根实例的 options 里
const router = new VueRouter() // 1
Vue.use(router) // 2
new Vue({router}) // 3
路由变化与组件渲染关联
每当路由变化, Router-View 组件都会重渲染。
关联思考
换个角度思考。先不思考怎样去关联。
问题:先想一下Router-View怎样才能重新渲染?
解决方向:毫无疑问,Router-View是用在Vue框架内,所以第一反应,想到的就是依赖发生变化。
问题:依赖关系如何产生?
解决方向:取个巧,我不直接与Router-View产生依赖关系,我与Router-View所在的组件产生依赖关系。
所以,我们能到下面的简图:

路由初始化并获取引用
const demo1 = Vue.component("demo1", { template: `<div>demo1</div>` });
const demo2 = Vue.component("demo2", { template: `<div>demo2</div>` });
const demo3 = Vue.component("demo3", { template: `<div>demo3</div>` });
class VueRouter{
constructor(options){
this.routers = options.routers;
this.current = null
this.comContain=[]
}
init(vueCompentInstance){
this.comContain.push(vueCompentInstance)
}
}
const router = new VueRouter({ routers: [demo1, demo2,demo3] });
const install = (Vue) => {
// 在每个组件的指定生命周期内,处理你想处理的事情
Vue.mixin({
beforeCreate() {
this._route = this.$parent
? this.$parent.$options.router
: this.$options.router;
//获取引用
this._route.init(this);
//建立依赖关系
Vue.util.defineReactive(this, "_route", this._route.current);
},
});
Object.defineProperty(Vue.prototype, "$router", {
get() {
return this.$options.router;
},
});
};
router.install = install;
Vue.use(router);
路由监控(hash)
// 以hash模式为例子,通过原生事件监控hash变化
class VueRouter{
constructor(options){
this.routers = options.routers;
this.current = null
this.comContain=[]
window.addEventListener("hashchange", (el) => {
const { newURL } = el;
const target = newURL.split("#");
// 手动匹配组件
if(target.length>0){
const t = target[1]
if(t==='a'){
this.update(this.routers[0])
}else if(t==='b'){
this.update(this.routers[1])
}else if(t==='c'){
this.update(this.routers[2])
}
}
})
}
// 初始化
init(vueCompentInstance){
this.comContain.push(vueCompentInstance)
}
// 刷新依赖
update(com){
this.comContain.forEach(route=>{
route._route=com
})
}
}
Router-View
选择了 Vue.compoent 的 functional 模式。
const regView = (Vue) => {
Vue.component("router-view", {
functional: true,
render(createElement, { props, children, parent, data }) {
const router = (parent.$router && parent.$router.routers) || [];
const component = parent._route;
if (!component) {
return createElement();
}
return createElement(component);
},
});
};
网友评论