一、准备工作
//定义三个组件:
const Home = { template: '<div>首页</div>' }
const pageOne = { template: '<div>pageOne</div>' }
const pageTwo = { template: '<div>pageTwo </div>' }
//定义一个路由数组
const routes = [
{
path: '/',
component: Home
},
{
path: '/pageOne ',
component: pageOne
},
{
path: '/pageTwo ',
component: pageTwo ,
}
]
//新建路由对象:
const router = new Router({
mode:'history',
routes:routes
});
var vue = new Vue({
el: '#app',
router
})
所以,上面的new Router()就是我们要实现的。
二、实现Router
根据上面的代码,可以看到Router是一个构造函数,接受一个参数。参数为一个对象,里面是我们定义的mode(路由模式),routers(路由数组)。
class vueRouter {
// 构造函数接受一个参数options,里面是我们定义的mode(路由模式),routers(路由数组)
constructor(options){
this.mode = options.mode || "hash";
this.routes = options.routes || [];
// 参数传进来的路由表数据格式不方便操作,封装一个createMap函数,来组装成
// {
// '路径': 组件,
// '路径': 组件
// }
// 键为路径,值为组件 的格式
this.routesMap = this.createMap(this.routes);
// 路由中需要存放当前的路径
this.history ={
current :null
};
// 开始初始化操作
this.init();
}
init(){
if(this.mode == 'hash'){
// 先判断用户打开时有没有hash,没有就跳转到#/
location.hash?' ':location.hash = '/';
// 页面加载完成时,存放当前的路径
window.addEventListener('load',()=>{
this.history.current = location.hash.slice(1);
//location.hash.slice(1) 路由#号之后的值
});
// hash路由改变时,存放当前的路径
window.addEventListener('hashchange',()=>{
this.history.current = location.hash.slice(1);
})
}else {//history模式同理 hash
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((memo,current)=>{
memo[current.path] = current.component
return memo
},{})
}
}
实现vueRouter Install
使用vue.use就会调用install方法。
vue每个组件都有this.$router / this.$route
所以要mixin一下。(还不了解vue mixin的可以看一下我简书中《vue mixin》的讲解)
vueRouter.install = function(Vue,opts) {
Vue.mixin({//混合方法
beforeCreate(){
if(this.$options && this.$options.router){ //定位跟组件
//把当前实例挂载在_root上
this._root = this;
// 把router实例挂载在_router上
this._router = this.$options.router
//history中的current变化也会触发
Vue.util.defineReactive(this,'xxx',this._router.history);
}else {
// vue组件的渲染顺序 父 -> 子 -> 孙子
this._root = this.$parent._root;//获取唯一的路由实例
}
Object.defineProperty(this,'$router',{//Router的实例
get(){
return this._root._router;
}
});
Object.defineProperty(this,'$route',{
get(){
return {
//当前路由所在的状态
current:this._root._router.history.current
}
}
})
}
});
// 全局注册 router的两个组件
Vue.component('router-link',{
props:{
to:String,
tag:String
},
methods:{
handleClick(){跳转方法
}
},
render(h){
let mode = this._self._root._router.mode;
let tag = this.tag;
return <tag on-click={this.handleClick}
href={mode === 'hash'?`#${this.to}`:this.to}>{this.$slots.default}
</tag>
}
})
Vue.component('router-view',{//根据当前的状态 current 对应相应的路由
render(h){
//将current变成动态的 current变化应该会影响视图刷新
//vue实现双向绑定 重写Object.defineProperty
let current = this._self._root._router.history.current;
let routeMap = this._self._root._router.routesMap
return h(routeMap[current])
}
})
}
export default VueRouter;
网友评论