目录

使用AI一步一步实现若依前端10

使用AI一步一步实现若依前端(10)

功能10:添加首页菜单项

功能9:退出登录功能
功能8:页面权限控制
功能7:路由全局前置守卫
功能6:动态添加路由记录
功能5:侧边栏菜单动态显示
功能4:首页使用Layout布局
功能3:点击登录按钮实现页面跳转
功能2:静态登录界面
功能1:创建前端项目

前言

一.操作步骤

1.修改router/index.js

给不需要显示的对象设置hidden属性,例如登录页。

给首页增加meta属性。

export这个初始化的路由数组,后面需要跟服务端返回的动态数组合并。

export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login.vue'),
    hidden: true
  },
  {
    path: '/',
    component: Layout,
    redirect: '/index',
    meta: { title: '首页', icon: 'House', affix: true },
    children: [
      {
        path: 'index',
        component: () => import('@/views/index.vue'),
        meta: { title: '首页', icon: 'House', affix: true }
      }
    ]
  }
]

2.修改stores/permission.js

拼接初始路由数组和后端返回的路由数组。

import { constantRoutes } from '@/router'

arrayForMenu.value = constantRoutes.concat(menuData)

3.修改MenuItem.vue

针对拼装的菜单数组,对首页对象做一些特殊处理。

<template>
    <div v-if="!item.hidden">
        <template v-if="hasChildren">
            <el-sub-menu :index="item.path">
                <template #title>
                    <el-icon v-if="item.meta?.icon">
                        <component :is="item.meta.icon" />
                    </el-icon>
                    <span>{{ item.meta?.title }}</span>
                </template>
                <template v-for="child in item.children" :key="child.path">
                    <MenuItem :item="child" :level="level + 1" :base-path="resolvePath(item.path)" />
                </template>
            </el-sub-menu>
        </template>

        <template v-else>
            <el-menu-item :index="resolvePath(item.path)">
                <el-icon v-if="item.meta?.icon">
                    <component :is="item.meta.icon" />
                </el-icon>
                <span>{{ item.meta?.title }}</span>
            </el-menu-item>
        </template>
    </div>
</template>

<script setup>
import { defineProps, computed } from 'vue';

const props = defineProps({
    item: {
        type: Object,
        required: true
    },
    level: {
        type: Number,
        default: 0
    },
    basePath: {
        type: String,
        default: ''
    }
});

const hasChildren = computed(() => {
    if (props.level >= 2) {
        if (props.item.children) {
            console.error('菜单层级超过限制,最多允许两层子菜单');
            return false;
        }
        return false;
    }
    if (props.item.path === '/') {
        return false
    }
    return props.item.children && props.item.children.length > 0;
});

const resolvePath = (routePath) => {
    if (props.basePath.length === 0) {
        return routePath
    }
    if (routePath === '/') {
        return '/index'
    }
    return getNormalPath(props.basePath + '/' + routePath)
}

/**
 * 路径标准化处理器
 * 功能: 规范化URL/文件路径格式,确保路径符合统一格式标准
 * 核心处理逻辑:
 * 1. 处理空值及无效路径
 * 2. 转换双斜杠为单斜杠
 * 3. 去除路径末尾的斜杠
 * 
 * @param {string} p - 原始路径字符串
 * @returns {string} 标准化后的路径
 */
const getNormalPath = (p) => {
    // 空值安全处理:当传入空值/undefined字符串时直接返回原值
    if (p.length === 0 || !p || p == 'undefined') {
        return p
    };

    // 双斜杠转换:替换路径中的双斜杠为单斜杠
    let res = p.replace('/\/+/g', '/')

    // 末尾斜杠清理:当标准化后路径以斜杠结尾时移除末尾斜杠
    if (res[res.length - 1] === '/') {
        return res.slice(0, res.length - 1)
    }
    return res;
}
</script>

二.功能验证

运行项目,浏览器访问http://localhost:5173/index

https://i-blog.csdnimg.cn/direct/010f9783ef3240cd817fa676d5e642bb.png