Vue-router个人封装使用

109 阅读2分钟

1. 基本使用

1. 安装vue-router
# --save表示添加到dependencies中,--save-dev表示添加到devDependencies中
pnpm install vue-router --save
2. 配置router/index.js文件
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '@/views/Home.vue'
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  }
]
const router = createRouter({
  history: createWebHashHistory(), // 配置路由模式: hash模式
  routes
})  
export default router
3. 配置main.js文件
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App);
app.use(router)
app.mount('#app')
4. 配置App.vue文件
<template>
  <div id="app">
    <router-view />
  </div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
</script>
5. 配置home.vue文件
<template>
  <div>
    <h1>Home</h1>
  </div>
</template>
<script setup>
</script>

2. 使用发布订阅模式配置拦截器

1. 编写发布订阅模式
// src/utils/pubsub.js
/**
 * 发布订阅模式监听注入
 * listeners: {
 *     // 路由 router事件
 *      router: beforeEach: [],
 *      router: afterEach: [],
 *      router: error: [],
 * }
 */
class PubSub {
    // 定义listeners对象,用于存储事件监听器
    listeners = {};

    constructor() {
        this.listeners = {};
    }

    /**
     * 订阅事件
     * @param eventName 事件名称,默认为空字符串
     * @param listener 事件监听器函数
     */
    on(eventName = '', listener) {
        if (!this.listeners[eventName]) {
            this.listeners[eventName] = [];
        }
        listener && this.listeners[eventName].push(listener);
    }

    /**
     * 取消订阅事件
     * @param eventName 事件名称,默认为空字符串
     * @param listener 事件监听器函数
     */
    off(eventName = '', listener) {
        if (!listener || !this.listeners[eventName]) {
            console.log('not on event ', eventName, 'or listener must be a function');
            return;
        }
        this.listeners[eventName].some((item, idx) => {
            if (item.name === listener.name) {
                this.listeners[eventName].splice(idx, 1);
                return true;
            }
            return false;
        });
    }

    /**
     * 发布事件
     * @param eventName 事件名称,默认为空字符串
     * @param args 传递给事件监听器的参数
     * @returns 事件监听器的返回值数组
     */
    emit(eventName = '', ...args) {
        if (!this.listeners[eventName]) {
            console.log('not on event ', eventName);
            return [];
        }
        const results = [];
        this.listeners[eventName].forEach((listener) => {
            const res = listener.apply(this, args);
            if (res !== undefined) {
                results.push(res);
            }
        });
        return results;
    }
}

const pubsub = new PubSub();

export default pubsub;

// 导出事件名称常量
export const ROUTER_BEFOREEACH = 'router:beforeEach';
export const ROUTER_AFTEREACH = 'router:afterEach';
export const ROUTER_ERROR = 'router:error';
2. 新增router/intercept.js文件,在对应的地方发布订阅事件
import pubsub, { ROUTER_BEFOREEACH, ROUTER_AFTEREACH, ROUTER_ERROR } from '@/utils/pubsub';

const intercept = (router) => {
    pubsub.on(ROUTER_BEFOREEACH, (to, from) => {
        // dosomething before each route
        console.log('beforeEach', to, from);
        return true;
    });
    pubsub.on(ROUTER_AFTEREACH, (to, from) => {
        // dosomething after each route
        console.log('afterEach', to, from);
    })
    pubsub.on(ROUTER_ERROR, (error) => {
        // dosomething when route error
        console.log('error', error);
    })
  // 路由进入前
  router.beforeEach((to, from, next) => {
    const result = pubsub.emit(ROUTER_BEFOREEACH, to, from);
    if (!result || result.some((item) => item === false)) {
      next(false);
    } else {
      next();
    }
  });
  // 路由进入后
  router.afterEach((to, from) => {
    pubsub.emit(ROUTER_AFTEREACH, to, from);
  })
  // 路由错误
  router.onError((error) => {
    pubsub.emit(ROUTER_ERROR, error);
  })
}

export default intercept;
3. 配置router/index.js文件
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import intercept from '@/router/intercept'
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  }
]
const router = createRouter({
  history: createWebHashHistory(), // 配置路由模式: hash模式
  routes
})
intercept(router)

3. 读取文件目录生成路由

1. 新增router/generate.js文件
/**
 * 读取目录结构生成路由配置
 */
import routeConfig from './config';
const generate = () => {
    const routes = [];
    const modules = import.meta.glob("@/views/**/*.vue");
    for (const [pathKey, moduleImport] of Object.entries(modules)) {
        if (pathKey.includes('components') || pathKey.includes('layouts')) {
            continue;
        }
        const matchResult = pathKey.match(/\/views\/(.*?)\.vue$/);
        if (!matchResult) {
            continue;
        }
        const pageName = matchResult[1];
        let idArr = pageName.split('/'), id = idArr[idArr.length - 1];
        const { name = id, meta = {} } = routeConfig[pageName] || {};
        routes.push({
            path: '/' + pageName,
            name,
            id,
            component: () => moduleImport().then(m => m.default), // 正确处理默认导出
            meta
        });
    }
    return routes;
}

export default generate;

4. 配置对应的路由信息,如 meta

// router/config.js
export default {
    'home': {
        name: '首页',
        meta: {
            title: '首页'
        }
    }
}

5. 最后完整的router/index.js文件


import { createRouter, createWebHashHistory } from 'vue-router';
import intercept from './intercept';
import generate from './generate';
const routes = [
  {
    path: '/',
    redirect: '/home'
  },
  ...generate()
];
console.log(routes);
const router = createRouter({
  history: createWebHashHistory(),
  routes
})
// 添加路由拦截器
intercept(router);

export default router