vue02-vueRouter实现原理

首先看一下vue-router得基本用法

router.js

import Router from 'vue-router'

Vue.use(Router);//应用插件做了什么????

export default new Router({//创建Router的实例  

  mode:'history',

  base:process.env.BASE_URL,

  routes:[ //配置routes

    {

      path:'/',

      name:'home',

      component:Home

    }

  ]

})

main.js

import router from 'router'

new Vue({

  router,//配置router实例(原因)???????????

}).$mount("#app")

app.vue

<div id="app">

  <div>

    <router-link to="/"></router-link>

  </div>

  <router-view></router-view>  

</div>

router-link和router-view哪来的??????????

以上为vur-router的基本用法,带着一些问题,我们看一下vue-router插件是如何实现的(只实现核心代码)

router的任务分析:

1.实现vue-router插件

2.解析下routes的选项

3.监控下url的变化(实现单页面不刷新的方法html5 history api和hash)

4.实现两个全局组件(router-link和router-view)

下面自己实现一个vue-router的插件

vue-router.js

//声明插件:vue插件需要实现一个install静态方法
let Vue;//保存Vue构造函数的引用,不对他产生直接的依赖,不将vue通过import进来不将vue打包进去
class VueRouter {
    constructor(options){
        this.$options = options;//实例中传入的数据
        this.routerMap = {};//路由的映射对象,即保存了数据,key味url,value为url对应得component {'/index':{component:Index,.....}}
        //获取当前的url
        //当前url需要是响应式的--值发生变化,所有用到值的组件都要刷新
        //此时借鉴Vue中data的响应式
        this.app = new Vue({
            data:{current:'/'}  //保存当前得url
        })
    }
    //初始化
    init(){
        //监听事件-----当页面
        this.bindEvent();
        //解析routes
        this.createRouteMap();
        //声明组件
        this.initComponent()
    }
    bindEvent(){
        window.addEventListener('hashchange',this.onHashchange.bind(this))
    }
    onHashchange(){
        this.app.current = window.location.hash.slice(1) || '/'
    }
    createRouteMap(){
        //遍历用户配置路由数组
        //根据地址拿到路由的配置对象
        this.$options.routes.forEach(route => {
            this.routeMap[route.path] = route
        })
    }
    initComponent(){
        //声明两个组件
        //声明组件的方法--为什么全局的声明就可以在任何组件中使用,而不需要在componets选项里配置???????
        //router-link的转换目标:<a href="/">xxx</a>
        Vue.component('router-link',{
            props:{
                to:String
            },
            //这里不可以用template来写
            //template:'<a></a>'
            render(h){
                //h(tag,data,children)
                //使用createEle函数
                return h('a',{
                    attrs:{href:'#'+this.to}
                },[this.$slots.default]) //[this.$slots.default]插槽代表上面的xxx内容

                //使用JSX
                //return <a href={'#'+this.to}>{this.$slots.default}</a>
            }
        })
        //获取path对应的Component将他渲染出来
        Vue.component('router-view',{
            render:(h) => {
                //拿出要渲染的component,然后再渲染出来
                //this指向组件的实例对象
                const Component = this.routerMap[this.app.current].component
                return h(Component)
            }
        })
    }
  
 /*
        Vue.component("router-view",{
            functional:true,
            render(h,{parent}){
                const router = parent.$router
                const Component = router.routeMap[router.app.current].component;
                return h(Component)
            }
        })
        */
}
//插件的use方法就是调用插件里的install方法(规定)
VueRouter.install = function(_Vue){ //参数是vue的构造函数
    Vue = _Vue;
    //实现一个混入---vue给我们提供了一个机制,让我们接下来写的生命周期的东西,将来会在vue组件的指定的声明周期中执行
    Vue.mixin({
        beforeCreate(){
            //获取到VueRouter的实例并挂载到Vue.prototype上
            if(this.$options.router){
                //根组件beforeCreate时执行一次
                Vue.prototype.$router = this.$options.router;//此处就是实现 你在组件中可以通过this.$router来进行一些操作
                this.$options.router.init()
            }
        }
    })
    //为什么引入一个混入,而不是直接将赋值语句直接放在install方法里??????
    //先执行的Vue.use(Router),(use执行了插件的install方法)此时实例Router还不在,所以把实例挂到根组件上,通过混入延后执行,延后到根组件beforeCreate的时候再执行
}

export default VueRouter
原文地址:https://www.cnblogs.com/znLam/p/12872964.html