vue-vueRouter+route-link + router-view简单实现

448 阅读3分钟

这是我参与更文挑战的第5天,活动详情查看: 更文挑战

注:以下是个人理解、如有不对还望指正!

认识vue-router

在单页面应用的年代、路由有着至关重要的地位、我们可以很容易的在一张路由表去配置我们每个页面的路由地址、长期使用vue、使得笔者非常好奇、vue-router的运行机制是什么样的、他是怎么实现管理路由的、为什么地址一变他就能过切换到对应的页面、所以开始吧!

正版vue-router的使用

  • 安装
yarn add vue-router 
//或
npm install vue-router
  • 初始化两个页面 目录:/src/router/index.js
import Vue from 'vue'
import Router from 'vue-router';
Vue.use(Router)

export default new Router({
    routes:[
        { path:'/home', component:() => import('../components/home') },
        { path:'/video', component:() => import('../components/video') },
    ]
})
  • main.js使用
import router from './router';
new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

然后在地址栏输入/home就进入home页面了、你在初始化页面的时候就要先创建好路由页面不然无法正确显示页面

重写vue-router

  • 在/router/下创建一个vue-router.js文件
let Vue;
class GfRouter {
    constructor( options ){
        this.$options = options;
        // 创建一个路由path和route映射
        this.routeMap = {};
        //利用vue的响应式 、把当前标签栏路由路径保存起来、默认为'/'
        this.routeApp = new Vue({
            data:{
                CURRENT_PATH:'/'
            }
        })
    }
    init(){
        //绑定浏览器路由事件
        this.bindEvents()
        //路由配置解析
        this.createRouterMap( this.$options );
        //创建router-view 和router-link 全局组件
        this.initComponent();
    }
    bindEvents(){
        // #号后面发生改变
        window.addEventListener('hashchange', this.onHashchange.bind( this ))
        // 页面加载完成
        window.addEventListener('load', this.onHashchange.bind( this ))
    }
    onHashchange(){
        //修改当前路由路径 修改完后因为vue是响应式 、只要用到CURRENT_PATH值的地方、那么其他地方都会跟着变、route-view里面也会跟着变
        this.routeApp.CURRENT_PATH = window.location.hash.slice(1) || '/'
    }
    createRouterMap( options ){
        options.routes.forEach( item =>{
            this.routeMap[ item.path ] = item;
        })
    }
    initComponent(){
        //全局组件
        Vue.component('router-link',{
            props:{
                to:String
            },
            render(h){
                // h渲染的函数、第一个参数渲染的标签  attrs 标签属性,第三个参数获取组件下的vnode
                return h('a', { attrs:{ href:'#/' + this.to } }, this.$slots.default)
            }
        })
        Vue.component('router-view',{
            //保存this  指向gfRouter实例
            render:(h) =>{ 
                //得到当前路径匹配的组件页面
                const Comp = this.routeMap[ this.routeApp.CURRENT_PATH ].component;
                return h( Comp )
            }
        })
    }
}
//写成插件
GfRouter.install = function( _Vue ){
    Vue = _Vue;
    // 混入扩展vue 、每个实例的this
    Vue.mixin({
        beforeCreate(){
            //只在根组件 实例化一次
            if( this.$options.router ){
                Vue.prototype.$router = this.$options.router;
                this.$options.router.init();
            }
        }
    })
}

export default GfRouter;

更换简易版路由文件

import Vue from 'vue'
import Router from './vue-router.js';
Vue.use(Router)

export default new Router({
    routes:[
        { path:'/home', component:() => import('../components/home') },
        { path:'/video', component:() => import('../components/video') },
    ]
})

实现的原理

首先我们创建了一个GfRouter路由类、然后初始化一个路由对象routerMap、和一个vue实例routeApp、里吗存放着一个当前路由路径变量CURRENT_PATH、然后执行init方法、监听浏览器路由事件和对开发者传入的配置路由表初始化、routeMap保存起路由表、在添加全局组件【router-link、router-view】、当我们的路由变化router-view组件就会通过当前保存的CURRENT_PATH命中路由表的.vue文件页面、然后由vue内部转成vnode后直接可通过render函数渲染到页面、整体流程不会太难理解、为什么需要new vue保存CURRENT_PATH变量的原因就是利用了vue的响应式原理、可以让我们动态的切换页面内容!

route-link组件

Vue.component('route-link',{
    props:{ to:String },
    render(h){
        // h渲染的函数、第一个参数渲染的标签  attrs 标签属性, 第三个参数 匿名插槽使用
        return h('a', { attrs:{ href:'#/' + this.to } }, this.$slots.default)
    }
  })

他的目的就是为了改变浏览器地址、从而让浏览器出发路由变化方法执行我们的onHashchange事件、替换CURRENT_PATH变量地址、从而让router-view更新最新页面地址、因为是简单版所以没有做很多的校验规则

router-view组件

 Vue.component('router-view',{
    //保存this  指向gfRouter实例
    render:(h) =>{ 
        //得到当前路径匹配的组件页面
        const Comp = this.routeMap[ this.routeApp.CURRENT_PATH ].component;
        return h( Comp )
    }
})

功能很简单、利用this.$slots.default获取编译好的vnode直接通过render函数渲染出去

添加常用方法push

//在类里在添加一个push方法
push ( path ) {
    window.location.hash = path
}

然后我们使用this.$router.push('/home')进行跳转、这样我们的一个简易版vue-router就实现了、当然我们也能在github上看vue-router的源码、他的实现很标准和规范、什么时候我也想能够写出那样好的结构代码、附带github源码地址

总结

实现的思路也在上面了、简易版实现起来并不是很难、准备深入学习下源码、学习设计思路、思想!