vue3动态路由搭建方法

1、为什么需要动态路由?

一般开发都是写静态路由,我们为什么要使用动态路由呢?因为动态路由对权限的划分是一个最有效的解决方法,下面我们就开始搭建一个动态路由的项目,使用技术是vite+ts+vue3+pinia+mock,mock主要用于模拟请求接口之后的处理,更接近实际项目

2、创建一个vite项目

yarn create vite

创建一个项目之后启动,具体启动过程初始化命令里面都会有提示的这里就不详细讲解了,删除里面的HelloWord.vue文件,这样一个空白项目就有了,下面我们先进行安装需要的插件

3、插件安装

需要安装vue-routerpiniaaxiosmock,我这边是使用的yarn安装的,如果使用npm安装也是可以的

//安装vue-router和axios、pinia
yarn add vue-router axios pinia
//安装mockjs和vite-plugin-mock。mock主要用途仅为模拟后端数据接口,所以安装为开发依赖,若打包为生产环境则会失效。
yarn add mockjs vite-plugin-mock

安装好插件之后,开始创建文件夹以及需要的文件

4、创建文件夹以及文件

4.1 在src下面新建router/index.ts:

import { RouteRecordRaw, createRouter, createWebHistory,createWebHashHistory } from 'vue-router'

// 静态路由表
const routes: Array<RouteRecordRaw> = [
    {
        // 路由重定向配置
        path: '/',
        redirect: '/Home'
    }, {
        path: '/Home',
        component: () => import('../views/Home.vue')
    }
]

// 路由对象
const router = createRouter({
    history: createWebHashHistory(),//hash路由
    routes
})

export default router

4.2 打开app.vue文件,改成如下代码:

<template>
  <router-view></router-view>
</template>

<script setup lang="ts"></script>

<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

4.4 在main.ts里面引入

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router' //引入router

const app=createApp(App)

app.use(router) //使用router

app.mount('#app')

这样就可以看到home页面了

4.5 模拟mock数据使用

4.5.1 创建/src/mock/index.ts

// /src/mock/index.ts
import { MockMethod } from "vite-plugin-mock"

const mock: Array<MockMethod> = [
    {
      url: '/api/test',
      method: 'get',
      response: () => {
          return {
              status: 200,
              message: 'success',
              data: '返回的数据'
          }
      }
    }
]

export default mock
4.5.2 配置vite.config.ts

要想使用mock,我们还需要在vite.config.ts文件下对mock进行配置,让vite启动的同时启动mock服务。

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { viteMockServe } from 'vite-plugin-mock'
 
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    // mock服务
    viteMockServe({
      supportTs: false,
      logger: false,
      mockPath: "./src/mock/",
    }),
  ]
})
4.5.3 配置axios

/src/utils/request.ts:此文件为axios配置文件,它将创建一个axios全局单例,由于本项目仅做最简单的演示,所以仅配置baseUrl,实际使用时可根据实际情况添加拦截器等功能。

import axios from 'axios'
// axios对象
const service = axios.create({
    // axios请求基础URL
    baseURL: "http://127.0.0.1:5175", //此处根据自己启动的端口来
    timeout: 5000
})
 
export default service

/src/apis/index.ts:此文件为接口文件,接口统一放到此文件中。

import req from '../utils/request'
 
/**
 * 测试接口
 */
 
// 测试用Hello World
export const TestApi = () => req({ url: '/api/test', method: 'get' })

home.vue代码修改如下

<template>
    <h1>Home</h1>
</template>
 
<script lang="ts" setup>
import { TestApi } from '../apis'
 
TestApi().then(res => console.log(res)).catch(err => console.log(err))
</script>

在这里就可以看到网络里面有接口请求成功了。

5、配置动态路由

5.1 配置动态路由接口

首先我们先在刚刚创建的mock接口文件/src/mock/index.ts中添加一个返回路由信息的路由接口,如下所示

import { MockMethod } from "vite-plugin-mock"

const mock: Array<MockMethod> = [
    {
      url: '/api/test',
      method: 'get',
      response: () => {
          return {
              status: 200,
              message: 'success',
              data: 'Hello World'
          }
      }
    },
    {
      url: '/api/getRoutes',
      method: 'get',
      response: () => {
        const routes = [
          {
              path: '/Page1',
              name: 'Page1',
              component: 'Page1/index'
          },
          {
              path: '/Page2',
              name: 'Page2',
              component: 'Page2/index'
          }
        ]
        return {
            status: 200,
            message: 'success',
            data: routes
        }
      }
    }
]

export default mock

/src/api/index.ts

import req from '../utils/request'

export const TestApi = () => req({ url: '/api/test', method: 'get' })

export const GetRoutes = () => req({ url: '/api/getRoutes', method: 'get' })

5.2 安装并配置pinia

piniavuex都是vue的全局状态管理工具,在前面的步骤已经安装了这个插件,我们就直接使用。
/src/store/index.ts代码如下

// /src/store/index.ts
import { defineStore } from 'pinia'
import { RouteRecordRaw } from 'vue-router'

//引入所有views下.vue文件 
let modules = import.meta.glob("../views/**")

// pinia状态管理器
export const useStore = defineStore('myStore', {
    state: () => {
        return {
            // 路由表
            routes: [] as Array<RouteRecordRaw>
        }
    },
    getters: {},
    actions: {
        // 添加动态路由,并同步到状态管理器中,这个地方逻辑是写的最简单的方式,大家可以根据自己的业务需求来改写,本质就是使用addRoute来实现
        addRoutes(data: Array<any>, router: any) {
            data.forEach(m => {
                this.routes.push({
                    path: m.path,
                    name: m.name,
                    // 错误示例:components:()=>import(`../views/Pages/${m.component}`)
                    // 正确示例如下:
                    component: modules[`../views/${m.component}.vue`],
                })
            })
            console.log('this.routes',this.routes)
            this.routes.forEach(m => router.addRoute(m))
        },
    }
})

main.ts代码如下

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
 
import { createPinia } from 'pinia'
const pinia = createPinia()
 
const app = createApp(App)
 
// 启用路由
app.use(router)
 
// 启用pinia
app.use(pinia)
 
app.mount('#app')

/src/views/home.vue代码如下

<template>
  <h1>Home</h1>
  <div style="display: flex; gap: 20px">
    <button v-for="item in routes" @click="handleClick(item.path)">
      {{ item.name }}
    </button>
  </div>
</template>

<script lang="ts" setup>
import { useStore } from "../store";
import { TestApi, GetRoutes } from "../apis";
import { useRouter } from "vue-router";
import { computed } from "@vue/reactivity";
import { onMounted } from "vue";

const router = useRouter();
const store = useStore();

// 动态路由表
const routes = computed(() => store.routes);

// 路由按钮点击事件
const handleClick = (path: string) => {
  router.push({ path });
};

onMounted(() => {
  if (store.routes.length < 1) {
    // 获取动态路由
    GetRoutes().then((res) => {
      store.addRoutes(res.data.data, router);
    });
  }

  // 测试接口
  TestApi()
    .then((res) => console.log(res.data))
    .catch((err) => console.log(err));
});
</script>

这样就实现了动态路由的跳转,但是这样直接刷新page1页面就会导致页面空白,所以我们是在路由拦截里面进行了处理

import { RouteRecordRaw, createRouter, createWebHashHistory } from 'vue-router'
import { useStore } from "../store";
import { GetRoutes } from '../apis'

// 静态路由表
const routes: Array<RouteRecordRaw> = [
    {
        // 路由重定向配置
        path: '/',
        redirect: '/Home'
    }, {
        path: '/Home',
        component: () => import('../views/Home.vue')
    }, {
        // 404页面配置
        path: '/:catchAll(.*)',
        component: () => import('../views/404.vue')
    }
]

// 路由对象
const router = createRouter({
    history: createWebHashHistory(),
    routes
})

// 路由守卫
router.beforeEach((to, from, next) => {
    if (to.path !== '/Home' && to.path !== '/') {
        const store = useStore()
        if (store.routes.length < 1) {

            GetRoutes().then(res => {
                store.addRoutes(res.data.data, router)
                next({ path: to.path, replace: true })

            }).catch(_ => {
                next()
            })

        } else {
            next()
        }
    } else {
        next()
    }
})

export default router

这样动态路由就搭建成功了。

ps:文章部分节选来源于网络

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值