1、vue-router使用规则
vue-router使用时 要调用Vue.use(VueRouter)
使用如下:
router/index.js
import VueRouter from '@/vue-router';
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
});
export default router;
// main.js
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
Vue.use函数式怎样的?
看源码
// Vue.use源码
// Vue源码文件路径:src/core/global-api/use.js
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)
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
installedPlugins.push(plugin)
return this
}
}
从源码中我们可以发现vue首先判断这个插件是否被注册过,不允许重复注册。
并且接收的plugin参数的限制是Function | Object两种类型。
对于这两种类型有不同的处理。
首先将我们传入的参数整理成数组 => const args = toArray(arguments, 1)。
// Vue源码文件路径:src/core/shared/util.js
export function toArray (list: any, start?: number): Array<any> {
start = start || 0
let i = list.length - start
const ret: Array<any> = new Array(i)
while (i--) {
ret[i] = list[i + start]
}
return ret
}
再将Vue对象添加到这个数组的起始位置args.unshift(this),这里的this 指向Vue对象
如果我们传入的plugin(Vue.use的第一个参数)的install是一个方法。也就是说如果我们传入一个对象,对象中包含install方法,那么我们就调用这个plugin的install方法并将整理好的数组当成参数传入install方法中。 => plugin.install.apply(plugin, args)
如果我们传入的plugin就是一个函数,那么我们就直接调用这个函数并将整理好的数组当成参数传入。 => plugin.apply(null, args)
以上可知 plugin.install函数第一个参数就是Vue参数,后面的参数才是传入参数
Vue.use(plugin)目的是为了执行plugin里面的install方法 并且传入Vue对象, 同时vue和vue-router中 vue版本和用户使用保持了一致性
2、编写vueRouter基本结构
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
});
2.1 上面使用可知,VueRouter是一个构造函数并且接受对象传参, 因此编写构造函数和init函数,传入的options就是我们new VueRouter参数对象, 拿到routes 要生成一个路径和组件的映射表,为了做组件渲染用。
// vue-router/index.js
import {
install } from './install';
import {
createMatcher } from './create-matcher';
import HashHistory from './history/hash';
import BrowserHistory from './history/history';
export default class VueRouter {
constructor(options) {
// 根据用户的配置 生成一个映射表 稍后跳转时 根据路径找到对应组件来进行渲染
// 创建匹配器后,核心的方法就是匹配
// match addRoutes
this.matcher = createMatcher(options.routes || []);
// 定义其中一个钩子函数队列, 其实有很多 先忽略其他
this.beforeEachHooks = [];
// 根据当前的mode 创建不同的history管理策略
switch (options.mode) {
case 'hash': {
this.history = new HashHistory(this);
break;
}
case 'history': {
this.history = new BrowserHistory(this);
break;
}
}
}
init(app) {
// app根实例
// 路由初始化
console.log('init');
}
}
VueRouter.install = install;
2.2 并且要符合Vue.use(VueRouter), 故VueRouter要增加install的函数, 稍后再讲解createMatcher、HashHistory、BrowserHistory。
2.3定义install函数
我需要将当前的根实例的提供的router属性 共享给所有子组件 Vue.prototype不好 会影响了全局的Vue实例 改用mixin
/*
* @description:
* @author: steve.deng
* @Date: 2020-12-22 07:19:31
* @LastEditors: steve.deng
* @LastEditTime: 2020-12-23 15:19:15
*/
// install.js
export let _Vue;
// 直接使用传入的vue 不需要引入了 版本也保持一直
export function install(Vue, options) {
_Vue = Vue;
//我需要将当前的根实例的提供的router属性 共享给所有子组件 Vue.prototype不好 会影响了全局的Vue实例 改用mixin
// 所有子组件初始化的时候 都会去调用
Vue.mixin({
beforeCreate() {
// 获取到每个人的实例 给实例添加属性
console.log(this.$options);
// 共用顶层this
if (this.$options.router) {
this._routerRoot = this; // 把根实例挂载到_routerRoot上
this._router = this.$options.router;
this._router.init(this);
console.log('this._route', this._route);
// this._router 路由实例
} else {
// this._routerRoot 指向当前根组件实例
this._routerRoot = this.$parent && this.$parent