手写简易vue-router

212 阅读1分钟

微信公众号:  [大前端驿站]
关注大前端驿站。问题或建议,欢迎公众号留言。 这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

Vue Router是Vue官方的路由管理器。它和Vue.js深度集成,让构建单页面应用变得易如反掌。

使用vue-router

Vue cli创建的vue项目中安装:vue add router

核心步骤:

  • 步骤一:创建router.js, 使用vue-router插件
import Router from 'vue-router'
Vue.use(Router)
  • 步骤二:创建Router实例
export default new Router({...})
  • 步骤三:main.js中的根组件上添加该实例
import router from './router'
new Vue({
  router,
}).$mount('#app')
  • 步骤四:在APP.vue中添加路由视图
<router-view></router-view>
  • 导航
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>

或者

this.$router.push('/')
this.$router.push('/about')

手写vue-router

实现⼀个插件:创建VueRouter类和install⽅法

我们先创建一个简单的vue-cli项目,然后来开始我们的手写过程

创建my-vue-router.js

let Vue

class VueRouter {
  constructor(options) {
   this.$options = options // 保存选项
  }
}

// 实现install方法,注册$router
VueRouter.install = function(_Vue) {
  Vue = _Vue // 引用构造函数

  // 使用混入方式是因为调用use的时间非常之早
  Vue.mixin({
    beforeCreate() {
      // 只有根组件拥有router选项
      if(this.$options.router) {
        Vue.prototype.$router = this.$options.router // 挂载$router
      }
    }
  })

  Vue.component('router-link', Link)
  Vue.component('router-view', View)
}

export default VueRouter

创建my-router-link.js

export default {
  props: {
    to: String,
    required: true
  },
  render(h) {
    //  <a href={'#'+this.to}>{this.$slots.default}</a>
    return h('a', {
      attrs: {
        href: '#' + this.to
      }
    },[
      this.$slots.default
    ])
  }
}

创建my-router-view.js

export default {
  render(h) {
    return h(null) // 暂时先不渲染任何内容
  }
}
监控url变化

定义一个响应式的属性current,监听hashonchange事件

import Link from './my-router-link.js'
import View from './my-router-view.js'

let Vue

class VueRouter {
  constructor(options) {
   this.$options = options // 保存选项

   const initial = window.location.hash.slice(1) || '/'
   Vue.util.defineReactive(this, 'current', initial)

   // 监听hashchange事件
   window.addEventListener('hashchange', this.onHashChange.bind(this))
   window.addEventListener('load', this.onHashChange.bind(this))

   // 优化:提前创建路由表,减少循环查询次数
   this.routeMap = {}
   this.$options.routes.forEach(route => {
     this.routeMap[route.path] = route
   })
  }

  onHashChange(){
    this.current = window.location.hash.slice(1)
  }
}

// 实现install方法,注册$router
VueRouter.install = function(_Vue) {
  Vue = _Vue // 引用构造函数

  // 使用混入方式是因为调用use的时间非常之早
  Vue.mixin({
    beforeCreate() {
      // 只有根组件拥有router选项
      if(this.$options.router) {
        Vue.prototype.$router = this.$options.router // 挂载$router
      }
    }
  })

  Vue.component('router-link', Link)
  Vue.component('router-view', View)
}

export default VueRouter

动态获取对应组件

// my-router-view.js
export default {
  render(h) {
    // 从注册的路由表中动态查询当前的组件
    // let component = null
    // const route = this.$router.$options.routes.find(route => route.path === this.$router.current)
    // if(route) {
    //   component = route.component
    // }
    const {routeMap, current} = this.$router
    const component = routeMap[current] ? routeMap[current].component : null
    return h(component)
  }
}

更改router/index.js中的router引用

// import VueRouter from 'vue-router'
import VueRouter from '../myRouter/my-vue-router'

启动项目看效果

vue-router.gif




~~感谢观看

关注下方【大前端驿站】
让我们一起学,一起进步

【分享、点赞、在看】三连吧,让更多的人加入我们~~