手写一个简单的vue-router

1. vue-router的使用

第一步:引入vue-router,并使用Vue.use加载

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

第二步:创建Router实例

export default new Router({routes: [{path: '/', component: Home}]})

第三步:在根组件上添加该实例,main.js

import router from './router'
new Vue({
 router,
 ...
}).$mount("#app");

第四步:使用路由视图

<!--导航-->
<router-link to="/">Home</router-link>
<!--路由出口-->
<router-view></router-view>

2.需求分析

根据vue-router的使用方法,我们需要做的事情有以下几点:
1.实现VueRouter类

  1. 保存传入的路由列表
  2. 监控url变化
  3. 响应url的变化

2.实现install方法给Vue.use调用

  1. 在Vue上挂载一个$router对象

3.创建两个全局组件

  1. router-link
  2. router-view

3.然后开始写代码

在写之前,先用vue-router写一个正常工作的页面,然后在src/router下面创建一个myrouter.js文件,最后改一下src/router/index.js文件,不引用vue-router,直接引用自己写的myrouter,这样做页面肯定报错,等写完myrouter.js,它又能正常运行,任务就完成了。

// import Router from 'vue-router'
import Router from './myrouter'

myrouter.js代码如下,思路顺序在注释中:

// 11 创建router-link
// 它是这样使用的:<router-link to="/">Home</router-link>
// 我们知道其实它是一个a标签,接收一个to属性,还有一个默认插槽
const Link = {
  // 接收to
  props: {
    to: {
      type: String,
      required: true
    }
  },
  // h是createElement方法,这个方法有三个参数,分别提供标签名,标签相关属性,标签内部的html内容 ,返回一个虚拟DOM
  // render方法可以使用JSX语法,但需要Babel plugin插件
  render (h) {
    return h('a', {
      attrs: {
        href: '#' + this.to
      }
    }, [this.$slots.default])
  }
}
// 12 创建router-view
const View = {
  // h方法还可以接收一个vue组件,在路由配置选项的routes中,所有需要渲染的路由组件都写在里面,
  // 在src/router/index.js中可以看到,在new Router的时候会传递进来,所以我们去构造方法中去保存一下路由
  // 14 拿到组件放到h中
  render(h) {
    let component = null
    if(this.$router.routerMap[this.$router.currentPath]) {
      component = this.$router.routerMap[this.$router.currentPath].component
    }
    return h(component)
  }
}



// 3 定义一个Vue,用来保存install中传入的Vue构造方法
let Vue

// 1 写一个class
export default class VueRouter{
  constructor(options) {
    // 6 获取当前url来对应路由里的path, 这里只做hash模式
    let currentPath = window.location.hash.slice(1) || '/'
    // 7 将currentPath做成响应式的,Vue.util.defineReactive(obj, key,...)的做用是将obj上的key弄成响应式的
    Vue.util.defineReactive(this, 'currentPath', currentPath)
    // 8 监听url变化,这里需要绑定一下this,不然就指到window上去了
    window.addEventListener('hashchange', this.onHashChange.bind(this))
    // 9 首次进入页面不会触发hashchange,需要用load来触发
    window.addEventListener('load', this.onHashChange.bind(this))
    // 13 保存一下options,它里面的值大概是这样的形式{routes: [{path: '/', component: Home}]}
    this.$options = options
    // 14 为了方便查找,做一个routerMap,不然每次找对应的组件都要循环routes
    this.routerMap = {}
    this.$options.routes.forEach(route => {
      this.routerMap[route.path] = route
    })
    // 16 调用一下
    this.createComponents()
  }
  // 10 url变化时,拿到hash值给currentPath
  onHashChange() {
    this.currentPath = window.location.hash.slice(1)
  }
  // 15 注册全局组件
  createComponents() {
    Vue.component('router-link', Link )
    Vue.component('router-view', View)
  }
}


// 2 在VueRouter上挂install方法
VueRouter.install = function(_Vue) {
  // 4 保存Vue ,从使用中可以看出,先是Vue.use(Router),然后才是new Router()
  // 所以是先执行install方法,后执行constructor,在这里保存Vue,构造函数中就可以使用Vue了
  Vue = _Vue
  // 5 挂载$router,使用全局混入,在main.js中,创建Vue时会传入router,其它组件是不会传入router的
  // 如果你其它的组件也放个router,这里就还需要判断一下Vue.prototype.$router是否已存在,因为根实例会先执行
  Vue.mixin({
    beforeCreate () {
      // 这里的this是Vue实例
      if(this.$options.router) { // 根组件
        Vue.prototype.$router = this.$options.router
      }
    }
  })
  // _15 在这里注册全局组件也是ok的
  // Vue.component('router-link', Like)
  // Vue.component('router-view', View)
}

再看下浏览器,是不是正常运行了?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值