手撕Vue-Router原理-实现自己的路由插件

1.路由总结

在这里插入图片描述
基础知识点是必须掌握的,无论在业务开发过程中还是准备面试复习,都需要扎实掌握。

手写路由插件-基础版

1.初始化一个vue项目
在这里插入图片描述
新建一个vuerouter文件夹,在文件夹中创建一个index.js文件,我们的vue插件就写在index中。
2.VueRouter的使用方式

	vue-router的基本使用方式:
	import Router from ‘vue-router’
	Vue.use(Router)
	export default new Router({
	mode: 'history',
	routes: [
		//路由规则
		]
	})
	main.js
	import router from './router'
	new Vue({
		router,
		render	: h => h(app)
	}).$mount('#app')

清楚了vue-router的使用方式,我们开始实现自己的vue-router功能
3.查看Vue.use()源码

/* @flow */

import { toArray } from '../util/index'

export function initUse (Vue: GlobalAPI) {
  Vue.use = function (plugin: Function | Object) {
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }

    // additional parameters
    const args = toArray(arguments, 1)
    args.unshift(this) //在第一个位置插入了Vue实例
    if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args)
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args)
    }
    installedPlugins.push(plugin)
    return this
  }
}

可以看到如果是对象就必须有install方法。
4.构建VueRouter
Vue.use() 方法中传入参数为函数或者对象,因此我们创建的VueRouter可以是函数也可以是对象,那么我们就以对象来创建。此次构建为history模式的路由。

let _Vue = null //设置全局保存Vue
export default class VueRouter {
	static install(Vue) {
		if(Vue.install.installed){ //判断是否以及安装了VueRouter
			return;
		}
		Vue.install.installed = true
		_Vue = Vue //全局保存,方便后面的代码调用
		//通过Vue的mixin 混入在Vue的原型上挂载VueRouter实例
		_Vue.mixin({
			beforeCreate() { 
				// this.$options.router 是 new Vue({
		        //   router 此处传递的router
		        // })
		        if(this.$options.router){ //如果存在 表示是通过 new Vue({router}) 来初始化的
		        	//组件初始化时不需要再次执行该代码
		        	_Vue.prototype.$router = this.$options.router		
		        	//调用初始化函数
		        	this.$router.init()		
				}
			}
		})
	}
	constructor(options) {
		this.$options = options;
		this.routeMap = {}; //路由映射关系
		this.data = _Vue.observable({ //设置该变量为响应式数据
			current: '/' //设置初始的路径
		})		
	}
	//设置路由映射表
	createRouteMap() {
		this.$options.routes.forEach((route)=>{
			this.routeMap[route.path] = route.component //路由路径和组件对应
		})
	}
	//注册全局的组件 router-link
	//router-link的使用:
	//<router-link to="/">首页</router-link>
	//因此需要to这个属性
	//并且内容自定义,需要使用slot插槽
	initComponent(Vue) {
		const self = this //保存 当前的this指向(指向的时VueRouter实例)
		Vue.component('router-link', {
			props: {
				to: {
					type: String,
					required: true
				}
			},
			//注意这里需要使用render函数来编译生成虚拟DOM
			//如果使用template 模板 在vue默认的版本中会出现报错,提示没有compiler
			//解决方法1.使用render函数创建组件,
			//2.在vue.config.js 中配置 runtimeCompiler: true 即可解决
			render(h) {
				// 默认使用a标签作为元素
				return h('a', {
					attrs: { //设置a标签的属性
						href: this.to //使用时传递的路径内容
					},
					//点击事件
					on: {
						click: this.clickHander
					}
				}, [this.$slots.default]) //通过$slots.default方法获取默认插槽中的内容
			},
			methods: {
				clickHander(e) { //点击事件
					//这里需要阻止a标签的默认事件,禁止点击时刷新页面,因为单页面路由是不需要请求后端的
					e.preventDefault()
					//通过history 提供的pushState()方法来控制路由
					history.pushState({}, "", this.to) //三个参数 state对象,标题,路径,前两个不需要管,只需要添加我们要去的路径即可
					//然后更新我们的响应式数据data中的current
					this.$router.data.current = this.to //注意该this代表的是 vue 实例因此有$router
				}
			}
		})
		//注册组件 router-view
		Vue.Component('router-view', {
			render(h) {
				return h(self.routeMap[self.data.current]) //此处就体现了该响应式数据的作用了,响应式就能让页面更新,当路径变化时就能更新视图,显示对应的组件	
			}
		})
	}
	
	initEvent() {
		//监听window的popstate事件 //MDN: 当活动历史记录条目更改时,将触发popstate事件
		//当我们点击前进或者后退时 会触发popstate事件
		window.addEventListener('popstate', ()=> { //此处需要使用箭头函数保证this指向为VueRouter
			this.data.current = window.location.pathname	
		})
	}
	//设置初始化函数,负责调用上面的三个方法
	init() {
		this.createRouteMap()
		this.initComponent(_Vue)
		this.initEvent()
	}
}

5.使用自定义的VueRouter
首先创建两个组件
在这里插入图片描述
然后创建router.js文件

import Vue from "vue";
import Router from './components/vuerouter'
import Login from './components/login'
import Home from './components/home'


Vue.use(Router)
export default new Router({
  mode: 'history',
  routes: [
    {path: '/', component: Home},
    {path: '/login', component: Login},
  ]
})

在main.js中使用

import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

App.vue
在这里插入图片描述
最后启动程序,页面如下:
在这里插入图片描述
点击login后
在这里插入图片描述
一个基础版本的VueRouter就创建成功了。后面会继续完善,比如路由嵌套等等。

路漫漫其修远兮,点个赞吧大哥

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值