美文网首页Vuereact & vue & angular
09、vue3动态路由搭建

09、vue3动态路由搭建

作者: 蜗牛的学习方法 | 来源:发表于2023-02-21 13:22 被阅读0次

    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页面了


    image.png

    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
    

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


    image.png
    image.png

    参考文章

    https://blog.csdn.net/XUMENGCAS/article/details/128036487

    相关文章

      网友评论

        本文标题:09、vue3动态路由搭建

        本文链接:https://www.haomeiwen.com/subject/yxbnkdtx.html