vue-router 的简易实现

965 阅读1分钟

vue-router

基础

vue-router 大家都不陌生,它是vue中核心生态之一。

  • 两种模式:hash 和history模式

  • 两个组件 router-link 和router-view

  • 两个常用方法属性 this.$routerthis.$routes

    • this.$router路由跳转。
    • this.$routes获取路由传参。
  • 三种导航钩子。

    • 全局导航钩子。
    • 路由独享导航钩子。
    • 组件导航钩子。

导航钩子的实现过于复杂,如果想探究vue-router的真正源码,可以参考 juejin.cn/post/684490…

简易实现

核心

hash 模式主要依赖监听hashchange方法。

使用Vue.Component 注册组件

使用Vue.util.defineReactive 将router置为响应式数据,一旦路径更新就可以更新视图

基础代码

const HASH='hash',HISTORY='history';
class History{
    constructor(current){
        this.current=current||'/home';

    }
}
class VueRouter{
     
    constructor(options){
        //模式

        this.mode=options.mode ||HASH;
        let routes=options.routes || [];
        this.routesMap=this.handleRoutes(routes);
        this.history=new History();
        this._init();


    }
    /**
     * 初始化
     */
    _init(){
        if(this.mode===HASH)
        {
            location.hash?'':location.hash='#/';
            //hash chanage
            window.addEventListener('hashchange',()=>{
             
                this.history.current=location.hash.slice(1);
                  
            })
            window.addEventListener('load',()=>{
                this.history.current=location.hash.slice(1);

            })

        }
        else if(this.mode===HISTORY)
        {
            location.pathname?'':location.pathname='/'
              window.addEventListener('popstate',()=>{
                 
                this.history.current=location.pathname;

                  
            })
            window.addEventListener('load',()=>{
                this.history.current=location.pathname;

            })

        }

    }

    handleRoutes(routes){

        var routesMap=routes.reduce((res,current)=>{
         
                res[current.path]=current.component;
                return res;
              

        },{});
        console.log(routesMap);
         return routesMap;

    }
  
}
/**
 * 安装
 * @param {*} Vue 
 */
VueRouter.install=(Vue)=>{
    
    Vue.mixin({
        beforeCreate(){
              //获得唯一的 router 实例
              //跟组件
                if(this.$options && this.$options.router)
                {
                    this._root=this.$options.router ||{};
                       // 将 _route 添加监听,当修改 history.current 时就可以触发更新了
                    
                     Vue.util.defineReactive(this, '_route', this._root.history)
                }
                else{
                    //子组件
                    
                    this._root=this.$parent && this.$parent._root||{};
                }
                console.log(this._root);
                Object.defineProperty(this,'$routes',{
                    get(){
                        return this._self._root
                    }

                })
                Object.defineProperty(this,'$router',{
                    get(){
                        return this._self._root.history.current;
                    }
                })

                }
            })
  

    //路由跳转

    Vue.component('router-link',{
          props:{
                to:String,
                required:true
          },
          render(h)
          {
               let mode=this._self._root.mode,to=this.to;
          return <a href={mode===HASH?`#${to}`:to}>{this.$slots.default}</a>
          }
     })
     //注册路由容器组件
     Vue.component('router-view',{
        render(h)
        {
            console.log(this._self)
            let current=this._self._root.history.current;
        
            if(!current)
            {
                return;
            }
            
            let component=this._self._root.routesMap[current];
             return h(component)
        }
   })



}
export default VueRouter;

结语

此处仅仅对vue-router的简易模拟,与真实源码相比差之千里,并无实际意义,不过简易实现可以让我们更加清楚其实现原理。以上是我学习中理解,如有错误,请谅解,欢迎批评指正。