一看就懂的vue-router简版源码

本文详细解析Vue Router的基本概念、安装与使用,重点在于简版Vue Router的源码实现,涵盖需求分析、必备知识及代码实现。通过实现VueRouter类,监听url变化,响应式替换视图内容,注册全局组件router-view和router-link,帮助读者深入理解Vue Router的工作原理。

1.Vue Router是什么?

Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举。功能包括:

  • 嵌套路由映射
  • 动态路由选择
  • 模块化、基于组件的路由配置
  • 路由参数、查询、通配符
  • 展示由 Vue.js 的过渡系统提供的过渡效果
  • 细致的导航控制
  • 自动激活 CSS 类的链接
  • HTML5 history 模式或 hash 模式
  • 可定制的滚动行为
  • URL 的正确编码

2.Vue Router的使用方式

安装: vue add router

核心步骤:

  • 步骤一:使用vue-router插件
 import Router from 'vue-router' 
 Vue.use(Router)
  • 步骤二:创建Router实例
 export default new Router({
 	routes: [{...}]
 })
  • 步骤三:在根组件上添加该实例
import router from './router'
new Vue({
	router,
}).$mount('#app')
  • 步骤四:添加路由视图
<router-view/>
  • 导航
<router-link to="/">helloWorld</router-link>
<router-link to="/source">源码</router-link>

3. Vue Router源码实现

3.1 ⭐️ 需求分析

根据上面的使用方式

Vue.use(Router) : 作为一个插件存在
export default new Router({…}) : vueRouter是一个类

vueRouter主要做的事情就是:监听路由的变化,当路由变化时,响应式的替换router-view中的视图内容。

所以我们自己写的这个简版的vue-router就需要满足以下需求:

  • 作为一个插件存在: 实现VueRouter类和install方法
  • 实现两个全局组件: router-view用于显示匹配组件内容,router-link用于跳转
  • 监控url变化: 监听hashchangepopstate事件
  • 响应最新url: 创建一个响应式的属性current,当它改变时获取对应组件并显示
3.2 🌷 准备知识:
  • 插件
  • 混入
  • 自定义组件

对以上不了的同学可以先看我之前的两篇文章:
vue进阶:混入mixin
vue进阶:使用插件实现弹窗类组件

3.3 🍀 代码实现

按照需求一,先写个类出来,并且作为一个插件

class VueRouter {
  constructor (props) {
    this.$options = props
  }
}

VueRouter.install = function (Vue) {
  _Vue = Vue
}

export default VueRouter

上面的类VueRouter的构造函数中的props,就是new Router({routes: [{…}]})中的{routes: [{…}]}

先来看install方法:

VueRouter.install = function (Vue) {
  _Vue = Vue

  // 1. 挂载$router
  Vue.mixin({
    beforeCreate () {
      // 只有根组件拥有router选项 所以这里判断下
      if (this.$options.router) {
        Vue.prototype.$router = this.$options.router
      }
    }
  })
}

vue 调用插件的时候,会给插件传递一个Vue实例,把这个保存下,便于在类实现中使用。挂载$router需要用到vue中的混入, 注意看上面的使用VueRouter的步骤代码, Vue.use(Router)在前,此刻还没有VueRouter实例,而install逻辑又需要用到该实例,所以这里使用混入,待beforeCreate时再去挂载 $router 实例。挂载该实例是为了在组件中能够拿到。

接下来实现下监听路由变化和存储路由表,便于在自定义组件router-view中渲染当前路径对应的component。

let _Vue
class VueRouter {
  constructor (props) {
    this.$options = props

    const initial = window.location.hash.slice(1) || '/'
    // 使current变成响应式
    _Vue.util.defineReactive(this, 'current', initial)

	// 处理path与route映射表
    this.routeMap = {}
    if (this.$options.routes) {
      this.$options.routes.forEach(route => {
        this.routeMap[route.path] = route
      })
    }

    // 监听hash路由变化
    window.addEventListener('hashchange', this.onHashChange)
  }

  onHashChange = () => {
  	// 只取 # 号后部分
    this.current = window.location.hash.slice(1)
  }
}

响应式这里使用了vue提供的Vue.util.defineReactive()方法。

然后就是实现注册组件router-view router-link了:

let _Vue
class VueRouter {
  constructor (props) {
    this.$options = props

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

    this.routeMap = {}
    if (this.$options.routes) {
      this.$options.routes.forEach(route => {
        this.routeMap[route.path] = route
      })
    }

    // 监听hash路由变化
    window.addEventListener('hashchange', this.onHashChange)
  }

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

VueRouter.install = function (Vue) {
  _Vue = Vue

  // 1.  挂载$router
  Vue.mixin({
    beforeCreate () {
      if (this.$options.router) {
        Vue.prototype.$router = this.$options.router
      }
    }
  })

  // 2.注册组件,router-view  router-link
  Vue.component('router-link', {
    render (h) {
      return h('a', {
        attrs: {
          href: '/#' + this.to
        }
      }, this.$slots.default)
    },
    props: {
      to: {
        type: String,
        required: true
      }
    }
  })

  Vue.component('router-view', {
    render (h) {
      const { routeMap, current } = this.$router
      return h(routeMap[current] ? routeMap[current].component : null)
    }
  })
}

export default VueRouter

知识点:
this.$slots.default: 获取组件的子节点

关键点:搞懂各个作用域内this的指向!

至此,一个基础的简版vue-router就实现了。这也是vueRouter官方实现的核心思路,这里看懂了,再去看源码会更简单很多。

♡ ♡ ♡ ♡ ♡ ♡
关注我,每日都有新收获!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值