【你应该知道的】你知道VueRouter的(路由跳转,router-link, router-view)怎么实现?

23,821 阅读3分钟

大家好,我是潘勇旭。我们又见面了,今天为大家带来了VueRouter的实现。大家的点赞是支持我写文章的源动力,希望来了能给大家带来不一样的东西,谢谢大家支持。

路由的配置 && 用法

// router.js
import Vue from 'vue'
import Router from 'vue-router'
//步骤1
Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      redirect: "/login"
    },]
    })
// main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
new Vue({
  // 步骤2 
  router,
  render: h => h(App)
}).$mount('#app')

以上就是我们vue-router的基本配置,从配置中我们看到vue-router的使用过程分为2步:

  • Vue.use(Router) Vue使用Router插件
  • Router实列添加到Vue.$options

插件的实现

vue-router作为插件,首先我们要实现插件的开发。Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:

let _Vue;
class VueRouter {
    constructor(options) {
       // ... 
    }
}

VueRouter.install = function (Vue) {
    // 避免重复注册
    if (VueRouter.installed && _Vue === Vue) return
    VueRouter.installed = true
    _Vue = Vue

    Vue.mixin({
        beforeCreate() {
            if (this.$options.router) {
                /**
                 *  this.$options.router === new Vue({
                        router,
                    })
                 *  */
                // 把路由实例挂载到Vue原型,以便在所有页面都能访问
                Vue.prototype.$router = this.$options.router
                this.$options.router.init()
            }

        }
    })
}

Vue.use(Router) 就是调用 `Router.install(Vue)`

VueRouter的实现

在上面我们可以看到,Vue.use(Router)之后,调用了我们的init()方法。所以现在我们需要来实现我们的init()

init() {
    // 绑定监听事件
    this.bindEvents()
    //  创建路由映射
     this.createRouterMap(this.$options)
    //  router-link routerlview 的实现
    this.initCompontents()
   
  }

init()我们可以分为三步进行实现:

  • 监听 hashchange 事件,维护路径修改后的值
  • 把路由文件router.routes对象进行映射,以便路由渲染时取出对应组件
  • 路由组件的实现

监听事件

路由我们是通过事件来触发,所以默认在load、hashchange绑定事件,当事件被触发维护当前路径

class VueRouter {
  constructor(options) {
    // 路由文件的配置
    this.$options = options
    // 路由映射map 
    this.routerMap = new Map()
    // path 维护当前页面路径key, 默认初始为 '/'
    this.app = new Vue({
      data() {
        return {
          path: '/'
        }
      },
    })
  }
  init() {
    // 绑定事件 
    this.bindEvents()
    // 创建路由映射
    this.createRouterMap(this.$options)
    // 创建组件
    this.initCompontents()

  }
  bindEvents() {
    // 绑定 hashchange  针对 hash 模式 '/#/xxx'
    window.addEventListener('hashchange', this.onHashChange)
    // 页面初始
    window.addEventListener('load', this.onHashChange)
  }
  onHashChange(e) {
    // 获取修改后的路径值 当前路径的path
    this.app.path = window.location.hash.slice(1) || '/'
  }
}

路由映射

我们通过维护this.routerMap这个对象,来保存路由配置文件的所有信息

    // router.js
    export default new Router({
          routes: [
            {
              path: '/',
              name: 'home',
              component: Home,
            },
            {
              path: '/ui',
              name: 'ui',
              component: UI,
            },
          ],
        });
        
    // vue-router.js
    createRouterMap(options) {
       // 维护router.js里配置
     /** this.routerMap =  [
            [ '/', {
                  path: '/',
                  name: 'home',
                  component: Home,
            },],
            [ '/ui', {
                  path: '/ui',
                  name: 'ui',
                  component: UI,
            },],
        ]*/
        
        options.routes.forEach(router => {
          this.routerMap.set(router.path, router)
        });
    }

全局组件实现

vue-router中,有两个全局组件,router-linkrouter-view ,router-link 实现的效果是通过一个 a标签进行跳转, router-view是对路由相对应的页面进行渲染。

 initCompontents() {
    // 实现 <router-link> 
    // <router-link to="/ui">去ui页面</router-link>
    Vue.component('router-link', {
      props: {
        // 组件通过props传入的跳转的路径
        to: {
          type: String,
        }
      },
      render(_h) {
        // _h 是 Vue createElement 方法
        // <a href = '#/ui' > 去ui页面 </a>
        return _h('a', { attrs: { 'href': '#' + this.to } },[this.$slots.default])
        
      }
    })
    // 实现 <router-view> 
    Vue.component('router-view', {
      render: (_h) => {
        // 通过路由映射对象取得跳转路径的组件 
        // router-view 标签进行占位 当有组件时就进行渲染
        const Comp = this.routerMap.get(this.app.path).component
        return _h(Comp)
      }
    })
  }

到目前为止,我们的简化版路由就实现了,在这个过程中,我们熟悉了Vue插件的开发,组件的创建以及事件处理。对我们的vue-router了解更深了一步,不但会用,我们也会写。我们大家一起进步

小伙伴们,你们的点赞是对我的支持和鼓励,对大家有帮助的可以留下你们的点赞支持鼓励我,谢谢大家。 祝大家新年快乐,万事如意。