23-完成登录页面跳转加载路由规则

第一次登录后首页空白

解决:第一次登录,动态添加路由规则

ts 复制代码
import {
    createRouter,
    createWebHashHistory,
    type RouteRecordRaw
} from 'vue-router'
import { type App } from 'vue'
import store from '../store'
import Cookie from 'js-cookie'

const routes: RouteRecordRaw[] = [
    {
        path: '/login',
        name: 'login',
        component: () => import('../views/login/login.vue')
    },
    // {
    //     path: '/home',
    //     name: 'home',
    //     component: () => import('../views/home/home.vue')
    // },
    // 动态生成的路由配置结构需要如下
    // {
    //     path: '/pms',
    //     name: 'pms',
    //     component: () => import('../views/home/home.vue'),
    //     children: [
    //         {
    //             path: 'product',
    //             name: 'product',
    //             component: () => import('../views/pms/product.vue'),
    //         }
    //     ]
    // }
]

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

// 根据 getters 里面的菜单生成路由规则
const genRoutes = () => {
    const menus = store.getters.getNewMenus;
    console.log('menus--->', menus)
    // const newRoutes:RouteRecordRaw[] = []
    // 循环菜单对象
    for(let key in menus) {
        const newRoute: RouteRecordRaw = {
            path: `/${menus[key].name}`,
            name: menus[key].name,
            component: () => import(`../views/home/home.vue`),
            redirect: `/${menus[key].name}/${menus[key].children[0].name}`,
            children: []
        }
        for(let i = 0; i < menus[key].children.length; i++) {
            newRoute.children?.push({
                path: menus[key].children[i].name,
                name: menus[key].children[i].name,
                component: () => import(`../views/${menus[key].name}/${menus[key].children[i].name}.vue`),
            })
        }
        // 动态添加路由规则
        router.addRoute(newRoute)
    }
    // 动态添加首页
    router.addRoute({
        path: "/",
        name: "home",
        component: () => import(`../views/home/home.vue`),
        redirect: '/index', // 访问 / 跳转到 /index 然后匹配上 index.vue
        children: [{
            path: "index",
            name: "index",
            component: () => import(`../views/index/index.vue`),
        }]
    })
    console.log('routes--->', routes)
}

// 前置导航守卫
router.beforeEach((to, from, next) => {
    // 1、token && vuex里面的 menus 为空
    const token = Cookie.get('token')
    console.log(store)
    if(token && store.state.menus.length === 0) {
        console.log('menus为空')
        // 获取用户信息
        store.dispatch('getAdminInfoApi').then(() => {
            genRoutes()
            // 路由规则没有刷新,需要再次next进入路由守卫
            next(to)
        })
    } else if(token && store.state.menus.length !== 0 && to.path === '/temp' && from.path === '/login') {
        // 第一次登录,动态添加路由规则 to.path === '/index' 要改成其他路由 /temp 避免登录进来进入 index 直接死循环
        genRoutes()
        // 路由规则没有刷新,需要再次next进入路由守卫
        next('/index')
    } else {
        next()
    }
})

export const initRouter = (app: App<Element>) => {
    app.use(router)
}
html 复制代码
<template>
    <div class="login-rule-form">
        <div class="content">
            <div class="title">商品管理系统</div>
            <el-form ref="ruleFormRef" :model="ruleForm" status-icon :rules="rules" label-width="60px">
                <el-form-item prop="username" label="账号">
                    <el-input v-model="ruleForm.username" type="text" placeholder="请输入账号"/>
                </el-form-item>
                <el-form-item prop="pwd" label="密码">
                    <el-input v-model="ruleForm.pwd" type="password" placeholder="请输入密码"/>
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" @click="loginFn()">登录</el-button>
                </el-form-item>
            </el-form>
        </div>
    </div>
</template>

<script lang='ts' setup>
import { onMounted, reactive, ref } from 'vue'
import { adminLoginApi } from '@/api/login'
import Cookie from 'js-cookie'
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex'

let ruleForm = reactive({
    username: "",
    pwd: ""
})
// 自定义密码校验规则(_variable - 未使用的变量 ts不校验)
const validatePwd = (_rule: unknown, value: string | undefined, callback: (msg?: string) => void) => {
    if(!value) {
        callback('密码不能为空')
    } else {
        callback()
    }
}
// 校验规则
let rules = reactive({
    username: [
        {
            required: true,
            message: '用户名不能为空',
            trigger: 'blur'
        }
    ],
    pwd: [
        {
            required: true,
            validator: validatePwd,
            trigger: 'blur'
        }
    ]
})

// 获取el-form组件对象
let ruleFormRef = ref()
// 获取项目路由对象
let router = useRouter()
// 获取当前项目的vuex对象
let store = useStore()

onMounted(() => {
    // console.log('组件实例:', ruleFormRef.value)
    // console.log('DOM 元素:', ruleFormRef.value?.$el)
})

// 点击登录
const loginFn = () => {
    ruleFormRef.value.validate().then(() => {
        adminLoginApi({
            username: ruleForm.username,
            password: ruleForm.pwd
        }).then((res) => {
            if(res.code === 200) {
                // 储存cookie
                Cookie.set('token', res.data.token, { expires: 7 })
                ElMessage.success('登录成功')
                // 获取用户信息
                store.dispatch('getAdminInfoApi').then(res => {
                    // 跳转首页的时候先跳转一个临时路由 /temp 去生成路由规则,然后在路由守卫里在去跳转 /index
                    router.push('/temp')
                })
            } else {
                ElMessage.error('登录报错')
            }
        })
    }).catch(() => {
        console.log('校验不通过')
    })
}

</script>

<style lang='less' scoped>
.login-rule-form {
    width: 100%;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: #f5f5f5;
    overflow: hidden;
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    .content {
        width: 420px;
        padding: 40px;
        background-color: #fff;
        border-radius: 8px;
        box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
        box-sizing: border-box;
        .title {
            font-size: 28px;
            font-weight: bold;
            text-align: center;
            margin-bottom: 30px;
        }
    }

    :deep(.el-form) {
        .el-form-item {
            margin-bottom: 20px;
            &:last-child {
                margin-bottom: 0;
            }
        }
        .el-button {
            width: 100%;
        }
    }
}
</style>
相关推荐
SL-staff3 天前
Vue3私有化AI白板落地实战|解决政企项目智能绘图合规难题(可直接复用源码)
人工智能·低代码·开源·vue3·白板·jvs规则引擎·jvs-draw
雨季mo浅忆3 天前
Cursor快速实现上传Excel功能
前端·vue3·ai编程
ANnianStriver5 天前
PetLumina-AI 驱动的宠物生活管理平台
java·生活·vue3·springboot·ai编程·宠物·全栈开发
雨季mo浅忆5 天前
记录Vue3项目中的各类问题
前端·bug·vue3
八目蛛8 天前
八目蛛网络(免费工具网站导航)
css·vue.js·开源·vue3·html5·ai编程
颂love8 天前
Vue3基础入门
前端·学习·vue3
海市公约9 天前
Vue3组合式API中watch传值生命周期与自定义Hook实战
vue3·生命周期·watch·props·组件通信·defineexpose·自定义hook
海市公约10 天前
Vue3组合式API与响应式系统核心机制详解
vue3·computed·reactive·ref·响应式系统·composition api·script setup
小茴香35311 天前
Vue3路由权限动态管理
前端·前端框架·vue3
暗冰ཏོ15 天前
《2026 Vue2 + Vue3 完整学习指南:基础语法、路由缓存、登录拦截、项目实战与面试题》
前端·vue.js·vue·vue3·vue2