zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    VBScript的参数引用
    异常处理规范
    测试感悟
    URL重写
    避免重复记录
    EJB 异常处理探试法
    EJB 异常处理的最佳做法(1)
    使用vbscript脚本调用web服务
    用Dom4j解析XML及中文问题
    lucene简介
  • 原文地址:https://www.cnblogs.com/znLam/p/12872964.html
Copyright © 2011-2022 走看看