19、springboot3 vue3开发平台-前端-面包屑和tabs动态事件处理

文章目录

1. 流程说明

  • 监控路由,通过路由和pinia 中缓存的菜单路由信息进行查询处理
    在这里插入图片描述
    其他处理见前边部分布局实现,包含tabs 的动态增改处理,面包屑过滤,逻辑处理整合到menu.ts中src\stores\menu.ts
import {defineStore} from 'pinia'
import {ref} from 'vue'
import { searchSelfMenusService } from '@/api/sys/menu'
import router from '@/router/index.js'
import Layout from '@/views/layout/Layout.vue'

let modules = import.meta.glob('../views/**/*.vue')

export const useMenuStore = defineStore("menu", () => {
    

    const menuList = ref<Array<any>>([])
    const routerList = ref<Array<any>>([])
    const menuArray = ref<Array<any>>([])                                           // 一维结构后菜单数组,便于菜单搜索

    const tabList = ref([{title:'首页',path:"/index",isClose: false, menuName: '首页'}])// 所有的tab
    const activeTab = ref('/index')                                      // 当前选中的tab,通过path体现
    const breadList = ref([{menuName: '首页', id: 0}])                  // 面包屑

     // 重载路由列表
    const generateRouterAndMenu = async () => {
        let menuResult = await searchSelfMenusService()
        // menuList.value = menuResult.data
        routerList.value = []   // 清除缓存
        initMenuAndRouter(menuResult.data, routerList.value)
        menuList.value = []
        contactChildRouter(menuResult.data, '')
        menuList.value = menuResult.data
        menuArray.value = flattenMenuTree(menuList.value)
        routeCheage(activeTab.value)                        // 刷新浏览器
    }

    const initMenuAndRouter = (menuList: Array<any>, routerList: Array<any>) => {
        modules = import.meta.glob('../views/**/*.vue')
        initRouterMountComponent(menuList, routerList)
        mountRouter()
    }

    const initRouterMountComponent = (menuList: Array<any>, routerList: Array<any>) => {
        menuList.forEach(item => {
            // 定义数据结构
            let routerInfo: any = {}
            if (item.componentPath) {
                if (item.children && item.children.length > 0) {
                    routerInfo = {
                        name: item.menuName,
                        path: item.path,
                        meta: {title: item.menuName},
                        // 设置组件,
                        component: modules[`../views/${item.componentPath}.vue`],
                        children: []
                    }
                } else {
                    routerInfo = {
                        name: item.menuName,
                        path: item.path,
                        meta: {title: item.menuName},
                        // 设置组件,
                        component: modules[`../views/${item.componentPath}.vue`]
                    }
                }
                // 将路由信息添加到数组中
                routerList.push(routerInfo)
            }
            // 递归子菜单
            if (item.children && item.children.length > 0) {
                initRouterMountComponent(item.children, routerInfo.children)
            }
        })
    }

    // 拼接子菜单完整路由
    const contactChildRouter = (list: Array<any>, parentPath: string) => {
        list.forEach(item => {
            if (parentPath != '') {
                let path = parentPath + '/' + item.path
                item.path = path
            } else {
                let path = "/" + item.path
                item.path = path
            }
            // 递归子菜单
            if (item.children && item.children.length > 0) {
                contactChildRouter(item.children, item.path)
            }
        })
    }

    // 挂载路由, 添加为/ 子路由, 在右侧主区域显示
    const mountRouter = () => {
        // 所有的页面都是加载到Layout/Main组件的RouterView中, 相当于所有的路由都是Layout的子路由
        router.addRoute(
            {
                component: Layout,
                path: "/",
                redirect: 'index',
                children: routerList.value
            }
        )
    }

    // 降维列表树,转为一维数组
    const flattenMenuTree = (tree: Array<any>): any[] => {  
        let result: any[] = [] 
        // 递归函数来遍历树并收集节点  
        let traverse = (nodes: Array<any>) => {  
            nodes.forEach(node => {  
                // 将当前节点添加到结果数组中  
                result.push({ ...node})
                if (node.children && node.children.length > 0) {  
                    traverse(node.children);
                }  
            })
        }    
        // 开始遍历树  
        traverse(tree)  
        return result;  
    } 

    // 移除路由菜单信息
    const removeMenuRouter = () => {
        menuList.value = []
        routerList.value = []
        menuArray.value = []
        initBreadcrumbAndTabs()
    }

    // 初始化面包屑
    const initBreadcrumbAndTabs = () => {
        tabList.value = [{title:'首页',path:"/index",isClose: false, menuName: '首页'}]   // 所有的tab
        activeTab.value = '/index'                                     // 当前选中的tab,通过path体现
        breadList.value = [{menuName: '首页', id: 0}]
    }

    // // 浏览器刷新,重新加载,解决路由丢失问题
    // const refresh = () => {
    //     // generateRouterAndMenu().then(() => {
    //     //     console.log('refersh=============', activeTab.value)
    //     // routeCheage(activeTab.value)
    //     // })  
    //     routeCheage(activeTab.value)
    // }
    
    // 设置tabList {title:'首页',path:'/index'}
    const addTab = (data: any) => {
        const checkTab: Array<any> = tabList.value.filter(item => item.path === data.path)
        if (checkTab.length === 0) {
            let tab = {title: data.menuName, path: data.path, isClose: false, menuName: data.menuName}
            tabList.value.push(tab)
        }
    }
    //删除tabList
    const delTabList = (path: string) => {
        let index = tabList.value.findIndex(obj => obj.path === path)
        // 删除并更新
        tabList.value = tabList.value.filter(item => {
            if(item.path == path) {
                return false
            }else {
                return true
            }
        })
        if (tabList.value.length == 0) {
            initBreadcrumbAndTabs()
            router.push(activeTab.value)
        }
        if (activeTab.value == path) {
            if (index > 0) {
                setActiveTab(tabList.value[index -1].path)
            } else {
                setActiveTab(tabList.value[index].path)
            }
            router.push(activeTab.value)
        }
    }

    // 设置activeTab
    const setActiveTab = (path: string) => {
        activeTab.value = path
    }

    // 关闭其他标签
    const colseOthersTabs = (path: string) => {
        tabList.value = tabList.value.filter(item => item.path == path)
        activeTab.value = path
        routeCheage(path)
        router.push(path)
    }

    // 添加面包屑数据
    const addBreadList = (item: any) => {
        breadList.value = searchParentPath(item, menuArray.value)

    }

    // 搜索父路径
    function searchParentPath(menu: any, menuArray: any[]) {  
        let result = [{ menuName: menu.menuName, id: menu.id }];  
      
        function traverse(node: any) {  
            const currentNode = menuArray.find(n => n.id === node.parentId);  
            if (currentNode) {  
                result.unshift({ menuName: currentNode.menuName, id: currentNode.id });  
                traverse(currentNode);  
            }  
        }  
      
        if (menu.parentId !== 0) {  
            traverse(menu);  
        }  
      
        return result;  
    }

    const routeCheage = (route: string) => {
        // 更新tabs
        const menus = menuArray.value.filter(item => item.path.includes(route))
        let match = menus.sort((a, b) => a.path.length - b.path.length)
        if (match.length > 0) {
            addTab(match[0])
            setActiveTab(route)
            // 更新面包屑
            addBreadList(match[0])
        }
        
        
    }


    return {
        menuList, routerList, tabList, activeTab, menuArray, breadList,
        generateRouterAndMenu, initMenuAndRouter, removeMenuRouter,
        initBreadcrumbAndTabs, addTab, delTabList, setActiveTab,
        colseOthersTabs, addBreadList, routeCheage
    }
},
{
    persist: {
        paths: ['activeTab']//指定要长久化的字段
      }
}
)
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不知所云,

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值