vue-router相关

522 阅读1分钟

一、vue-router拓展

1.1 addRoutes实现动态路由

router.addRoutes(routes: Array),常用于权限控制,例如会员访问的菜单区分。
关键点:接口传过来的component为字符,并不是对象,需要映射为对象。

api.getRoutes.then(res=>{
    const routesConfig = res.routes.map(route=>{
        mapComponent(route);
    })
    this.$router.addRoutes(routesConfig)
})
let mapCom = function(com){
  return {
      com:()=>import(`@/view/${com}`);
  }  
}
let mapComponent = function(route){
    const route.component = mapCom(route.component);
    if(route.children){
        route.children = route.children.map(child=>{
            mapComponent(child);
        })
    }
}

1.2 面包屑

面包屑常用于网页的定位,例如首页->列表页,因此可以利用route.matched匹配当前路由的信息。
知识点:$route.matched指当前路由的所有嵌套路径片段的路由记录。当 URL 为 /foo/bar,$route.matched 将会是一个包含从上到下的所有对象 (副本)。

watch:{
    $route:{
        handler:function(){
            this.crumbData = this.$route.matched.map(item=>{
               return {name:item.meta.name,path:item.meta.path}
            });
        },
        immediate:true
    }
}

1.3 简单版vue-router源码实现

  • 开发插件
    通过全局方法 Vue.use() 使用插件。它需要在你调用 new Vue() 启动应用之前完成。Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:
MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或 property
  Vue.myGlobalMethod = function () {
    // 逻辑...
  }

  // 2. 添加全局资源
  Vue.directive('my-directive', {
    bind (el, binding, vnode, oldVnode) {
      // 逻辑...
    }
    ...
  })

  // 3. 注入组件选项
  Vue.mixin({
    created: function () {
      // 逻辑...
    }
    ...
  })

  // 4. 添加实例方法
  Vue.prototype.$myMethod = function (methodOptions) {
    // 逻辑...
  }
}
  • 代码实现
    实现router-view、router-link组件,获取path与route的映射表,从而获取current的path后,能得到相应的component,current一定要为响应式的。
let Vue;
export default class vueRouter{
    constructor(options){
        this.options = options;
        this.routeMap = {};
        this.app = new Vue({
            data: {
                currentPath: '/'
            }
        })
    }
    init(){
        this.bindEvents();
        this.initComponent();
        this.createMatch();
        this.onHashChange();
    }
    onHashChange(){
        this.app.currentPath = window.location.hash.slice(1)||'/';
    }
    bindEvents() {
        window.addEventListener('hashchange', this.onHashChange.bind(this))
        window.addEventListener('load', this.onHashChange.bind(this))
    }
    initComponent(){
        const self = this;
        Vue.component('router-link',{
            render(h) {
                return h('a',{attrs:{href:`#${this.to}`}},this.$slots.default)
            },
            props:{
                to:String
            }
        })
        Vue.component('router-view',{
            render:h => {
                const com = self.routeMap[this.app.currentPath].component;
                console.log(com)
                return h(com);
            }
        })
    }
    createMatch(){
        this.options.routes.map(route=>{
            // 路径和route映射
            this.routeMap[route.path] = route;
        })
    }

}
vueRouter.install = function(_Vue){
    Vue = _Vue;
    Vue.mixin({
        beforeCreate() {
            if(this.$options.router!==undefined){
                this.router = this.$options.router;
                this.router.init()
            }
        }
    })

}