vue3+vite动态路由的实现

发布于:2024-04-17 ⋅ 阅读:(30) ⋅ 点赞:(0)

之前写过一个一篇关于vue3 cli的文章,状态管理用的vuex,需要参考的可以看下vue3动态路由的实现

现在把项目换成vite,有些地方不同,关于路由的处理也有所改变,所以重新记录一下

需要用到js-cookiepinia

一、登录请求获取路由信息

//点击登录按钮
const submitLogin = async () => {
  const res = await http.post('/login', loginForm.value)
  let token = res.data.data.token
  Cookies.set('token', token)

  let res2 = await http.get('/router')
  if (res2.data.code === 0) {
    let routers = res2.data.data
    if (routers) {
      //存路由信息
      localStorage.setItem('routerData', JSON.stringify(routers))
    } else {
      $message.warning('账号无权限,请联系超级管理员');
    }

    useLoginStore().setIsLogin(true)//存登录状态
    $message.success('登录成功');

    if (redirectUrl.value) {
      await router.push(redirectUrl.value)
    } else {
      await router.push({
        path: "/home"
      });
    }
  }
}

二、渲染路由

router/index.js中定义基本的路由信息,动态生成的路由默认放在Home组件。

Home组件包含最基本的布局,如菜单,header

import { createRouter, createWebHashHistory } from "vue-router";
import Cookies from "js-cookie";
import { storeToRefs } from "pinia";
import { useLoginStore } from "@/stores/modules/login";
import { useAxiosArrStore } from "@/stores/modules/axiosArr";
import dealWithRoute from "./dealWithRoute";

import Home from "../layout/Home.vue";

const routes = [
  {
    path: "/login",
    component: () => import("../views/login/Login.vue"),
    meta: {
      title: "登录",
    },
  },
  {
    path: "/register",
    component: () => import("../views/login/Register.vue"),
    meta: {
      title: "注册",
    },
  },
  {
    path: "/",
    name: "home",
    component: Home,
    redirect: "/home",
  },
  {
    path: "/:pathMatch(.*)*",
    component: () => import("../components/404.vue"),
  },
];

const router = createRouter({
  history: createWebHashHistory(),
  routes,
});

router.beforeEach((to, from, next) => {
  //asyncRoutesMark:是否加载了路由信息,为false则要请求路由接口
  //isLogin:登录状态
  let { asyncRoutesMark, isLogin } = storeToRefs(useLoginStore());
  let isLoadRouters = asyncRoutesMark.value;
  let token = Cookies.get("token");

  if (token && isLogin.value) {
    if (isLoadRouters) {
      //登录成功后不能通过历史箭头返回登录页面
      if (to.path !== "/login") {
        next();
      } else {
        //如果刚好url变成/login,重置from的path
        next({ ...from, replace: true });
      }
    } else {
      useLoginStore().setAsyncRoutesMark(true);

      //重新请求路由信息,解决刷新页面空白
      useLoginStore().getRouterInfo();
      if (localStorage.getItem("routerData")) {
        const routerData = JSON.parse(localStorage.getItem("routerData"));
        dealWithRoute(routerData);
      }

      //避免刷新页面后重要数据丢失
      //...可发起一系列请求

      next({ ...to, replace: true });
    }
  } else {
    useLoginStore().setAsyncRoutesMark(false);
    if (to.path === "/login" || to.path === "/register") {
      useAxiosArrStore().clearAxiosArr(); //假如页面有长链接请求,要取消
      next();
    } else {
      next("/login");
    }
  }
});

export default router;

router/dealWithRoute.js动态添加路由 

Vite 是一个基于 ES Module 的前端构建工具,它使用了静态导入的概念。在静态导入中,所有的导入路径都应该是静态字符串,不应该包含任何动态变量或表达式。

因为我们的路由是动态添加的,在使用import函数时,要确保导入的表达式是一个静态字符串component: () => import(path)

import router from "./index";
import { RouterView } from "vue-router";

const dealWithRoute = (data, parent = "home") => {
  if (data) {
    for (let item of data) {
      if (item.children && item.children.length > 0) {
        router.addRoute(parent, {
          path: item.path,
          name: item.path.split("/")[1],
          component: RouterView,
          meta: {
            title: item.name,
            requiresAuth: true,
          },
        });
        dealWithRoute(item.children, item.path.split("/")[1]);
      } else {
        //特殊情况特殊处理
        item.component_ = item.component.replace(".vue", "");
        let filePath = `../views/${item.component_}.vue`;

        router.addRoute(parent, {
          path: item.path,
          name: item.path.split("/")[1],
          component: () => import(filePath),
          //component: () => import(`../views/${item.component}`),//vue cli 写法
          meta: {
            title: item.name,
            requiresAuth: true,
          },
        });
      }
    }
  }
};
export default dealWithRoute;

 三、状态管理

//login.js
import {defineStore} from 'pinia'
import http from "../../api/http";
import Cookies from "js-cookie";

export const useLoginStore = defineStore('login', {
    state: () => ({
        routerData: [],//路由数据
        isLogin: sessionStorage.getItem('isLogin'),//登录状态
        asyncRoutesMark: false,//是否加载了路由信息,为false则要请求路由接口
    }),
    actions: {
        setRouters(data) {
            this.routerData = data;
        },
        setIsLogin(data) {
            this.isLogin = data
        },
        setAsyncRoutesMark(data) {
            this.asyncRoutesMark = data;
        },
        getRouterInfo() {
            http.get('/menu/router').then(res => {
                if (res.data.code === 0) {
                    this.routerData = res.data.data
                    localStorage.setItem('routerData', JSON.stringify(this.routerData))
                }
            })
        },
    }
})
//axiosArr.js
import {defineStore} from 'pinia'

export const useAxiosArrStore = defineStore('axiosArr', {
    state: () => ({
        axiosArr: []
    }),
    actions: {
        setAxiosArr(cancelAjax) {
            this.axiosArr.push(cancelAjax.cancelToken)
        },
        clearAxiosArr() {
            this.axiosArr.forEach(item => {
                item()
            })
            this.axiosArr = []
        },
    }
})


网站公告

今日签到

点亮在社区的每一天
去签到