vue-router 造轮子 01

267 阅读1分钟

先看流程图

vue-router 源码解析.png

按照 步骤 我们先创建一个基础的 vue 框架

创建项目
vue create app
安装依赖
npm i
添加路由
npm i vue-router
vue add router
运行项目
npm run serve

赋值 rule 更改名字

image.png

**创建router.js 来编写 router组件 ** 把 VueRouter 组件引用改为我们自己的 js目录

image.png 创建组件

let vue;
class VueRouter{
    constructor(options){
        
    }
}
VueRouter.install = function(_vue){

}
export default VueRouter;

options 对应的值是

image.png

install 注册组件 组件是通过 use 挂载在vue上 可以引用下 vue

这时候就可以运行项目 看下对应的log
这时候会报错router-link 和 route-view不存在

在install 里通过 引用的 vue 创建 component

`

VueRouter.install = function(_Vue) {
    Vue = _Vue;
    Vue.component("router-link", {
        render(h) {
            return h('a',{},'')
        },
    });
    Vue.component("router-view", {
        render(h) {
          return  h('div',{},1111)
        },
    });
};

接下来把router-link看成a标签带有herf属性 属性值是组件的to属性值 对应的内容是 组件插槽的值

vue.component("router-link",{
        props:{
            to:String,
            request:true
        },
        render(h){
            return h("a",{
                attrs:{
                    href:"#"+this.to
                }
            },this.$slots.default) 
        }
    })

接下来 要监听 rul hash 的变化 同时用个响应式对象来 保存它

  constructor(options){
        this.$options = options;
        console.log(window.location.hash.slice(1));

      
        const hashInit =  window.location.hash.slice(1) || '/';
        //创建一个响应式对象
        vue.util.defineReactive(this,'hashInit',hashInit);
        window.addEventListener('hashchange',this.hashChange.bind(this));
        window.addEventListener('load',this.hashChange.bind(this))
    }

    hashChange(){
        this.hashInit = window.location.hash.slice(1);
        console.log(this.hashInit)
    }

创建响应式对应 有多重方法

方法一
new vue({
    data(){
        return {
            创建
        }
    }
})
方法二
vue.util.defineReactive(this, target,value)

应为我们在使用路由时是先 use引用 后才创建vue实例
所有我们需要通过mixin在vue初始化时候把接收的options.router 挂载到vue上

//挂载在vue 初始化实例
    vue.mixin({
        beforeCreate(){
            if(this.$options.router){
                vue.prototype.$router = this.$options.router;
            }
        }
    })

接下来就是router-view展示对应路由的 template
我们已经通过options获取到对应路由的component 同时也通过响应式对象保存了hash最新值
只需要把 options 里对应等于 hash 值的component 取出来 渲染就可以了

  vue.component("router-view",{
        render(h){
            let component = null
            //判断时候有对应hash 的路由
            const route = this.$router.$options.routes.find(
                (router)=>{
                    return router.path === this.$router.hashInit;
                }
            );
            //有就把component取出来
            if (route) {
              component = route.component
            }
            //渲染
            return h(component) 
        }
    })

完整代码

let vue;

// import Home from '../views/Home.vue'


class VueRouter{
    constructor(options){
        this.$options = options;
        console.log(window.location.hash.slice(1));

      
        const hashInit =  window.location.hash.slice(1) || '/';
        //创建一个响应式对象
        vue.util.defineReactive(this,'hashInit',hashInit);
        window.addEventListener('hashchange',this.hashChange.bind(this));
        window.addEventListener('load',this.hashChange.bind(this))
    }

    hashChange(){
        this.hashInit = window.location.hash.slice(1);
        console.log(this.hashInit)
    }
}

VueRouter.install = function(_vue){

    vue = _vue;

    
    //挂载在vue 初始化实例
    vue.mixin({
        beforeCreate(){
            if(this.$options.router){
                vue.prototype.$router = this.$options.router;
            }
        }
    })

   
    vue.component("router-link",{
        props:{
            to:String,
            request:true
        },
        render(h){
            return h("a",{
                attrs:{
                    href:"#"+this.to
                }
            },this.$slots.default) 
        }
    })

    vue.component("router-view",{
        render(h){
            let component = null
            const route = this.$router.$options.routes.find(
                (router)=>{
                    return router.path === this.$router.hashInit;
                }
            );
            if (route) {
              component = route.component
            }
            return h(component) 
        }
    })

}



export default VueRouter;