Ant Design V5 menu导航栏点击跳转03 功能实现

基于上一篇的内容,本篇将所有功能进行了完善:

  • 顶部一级导航栏和左侧二级侧边栏联动
  • 通过浏览器url访问页面时 同步两个菜单的选中项
// SideBar.js
import { Menu } from 'antd'

function SideBar(props) {
    return (
        <Menu
            onClick={props.onClick}
            defaultSelectedKeys={[props.selectKey]}
            defaultOpenKeys={[props.openKey]}
            mode="inline"
            items={props.items}
        />
    );
}

export default SideBar
// MainLayout.js
import { Outlet } from 'react-router-dom'
import { Layout } from 'antd'
import { AppstoreOutlined, MailOutlined, SettingOutlined } from '@ant-design/icons'
import { useNavigate, useLocation } from "react-router-dom"
import { useState, useEffect } from 'react'

import HeadBar from '../../components/HeadBar'
import SideBar from '../../components/SideBar'

import { headerStyle, contentStyle, siderStyle, footerStyle } from './layoutStyles.js'

const { Header, Footer, Sider, Content } = Layout

const menuList = [
    {
        label: 'home',
        key: 'home',
        icon: <MailOutlined />,
        sidelist: []
    },
    {
        label: 'about',
        key: 'about',
        icon: <AppstoreOutlined />,
        sidelist: [
            {
                key: 'aboutMe',
                icon: <AppstoreOutlined />,
                label: 'aboutMe'
            },
            {
                key: 'myReading',
                icon: <MailOutlined />,
                children: [
                    {
                        key: 'englishBooks',
                        icon: <AppstoreOutlined />,
                        label: 'englishBooks'
                    },
                    {
                        key: 'chineseBooks',
                        icon: <SettingOutlined />,
                        label: 'chineseBooks'
                    },
                ],
                label: 'myReading'
            }
        ]
    }
]

function MainLayout() {

    /** 
      * 整个页面的Menu跳转逻辑分两块:
      * 当通过url访问页面时,menu的默认选中根据url走
      * 当点击menu item 的时候,根据点击的item 跳转页面。
      * 
      * 侧边栏的逻辑:当location发生变化时,查看当前url对应的顶部导航栏是否有侧边栏
      * 如果有:
      * 显示侧边栏组件 向侧边栏组件传值:defaultSelectedKeys defaultOpenKeys items onClick事件
      * 如果没有:
      * 隐藏侧边栏组件
      */
    const navigate = useNavigate()
    const location = useLocation()
    const [headBarCurrent, changeHeadBarCurrent] = useState('')
    const [clickChange, changeClickChange] = useState(null)
    const [showSideMenu,changeShowSideMenu] = useState(false)
    const [sideBarType,changeSideBarType] = useState({selectKey:'',openKey:''})
    const [sideBarList,changeSideBar] = useState()

    // 匹配和路径对应的key
    function getKey(key='',item,path,result=[]){
        item.map(e=>{
            if (e.children && e.children.length) {
                getKey(e.key,e.children, path, result)
            } else if (path.indexOf(e.key) !== -1) {
                result.push(e.key,key)
            }
        })
        return result
    }

    useEffect(() => { // 当location发生变化时 需要更改菜单选中值 并判断有无侧边栏
        const path = location.pathname
        menuList.map(e => {
            const key = e.key
            if (path.indexOf(key) !== -1) { // 获取对应的顶层导航栏
                changeHeadBarCurrent(key)
                const side = e.sidelist
                if(side.length){ // 顶层导航栏有子菜单的情况下 检索对应项
                    const sideMenuKey = getKey('',side,path)
                    changeSideBar(side) // 设置子菜单的数据
                    changeSideBarType({
                        selectKey:sideMenuKey[0],
                        openKey:sideMenuKey[1] ? sideMenuKey[1] : sideMenuKey[0] // 如果没有父级,说明没有子级菜单
                    })
                    console.log('=== sideBarType ===',sideBarType)
                    changeShowSideMenu(true) // 显示侧边栏
                } else {
                    changeShowSideMenu(false) // 不显示侧边栏
                }
            }
        })
    }, [location])

    useEffect(() => { // 在菜单点击事件发生时
        if (clickChange) { // 跳转页面
            navigate(clickChange)
        }
    }, [clickChange])

    const onSideBarClick = (e) =>{
        const url = '/'+headBarCurrent+'/'+e.key
        changeClickChange(url) // 告知触发了菜单点击事件 需要跳转页面了
    }

    const onHeadBarClick = (e) => { // 当顶部导航栏触发点击的时候 需要更新两个值
        changeHeadBarCurrent(e.key) // 告知菜单选中值发生了变化
        const url = '/' + e.key
        changeClickChange(url) // 告知触发了菜单点击事件 需要跳转页面了
    }

    return (
        <div>
            <Layout>
                <Header style={headerStyle}><HeadBar menuList={menuList} current={headBarCurrent} onClick={onHeadBarClick} /></Header>
                <Layout>
                    {showSideMenu ? <Sider style={siderStyle}><SideBar items={sideBarList} onClick={onSideBarClick} selectKey={sideBarType.selectKey} openKey={sideBarType.openKey} /></Sider> : '' }
                    <Layout>
                        <Content style={contentStyle}>
                            <Outlet />
                        </Content>
                        <Footer style={footerStyle}>footer</Footer>
                    </Layout>
                </Layout>
            </Layout>
        </div>
    )
}

export default MainLayout
// router
const router = createBrowserRouter([
    {
      path: "/",
      element: <MainLayout />,
      children: [
        {
          index: true, //  match on parent, i.e. "/"
          element: <Navigate to="/home" replace /> //  redirect
        },
        {
          path: "home",
          element: <Home />,
        },
        {
          path: "about",
          element: <About />,
          children:[
            {
              index:true,
              element:<Navigate to="/about/aboutMe" replace />
            },
            {
              path:'aboutMe',
              element:<AboutMe />
            },
            {
              path:'englishBooks',
              element:<EnglishBooks />
            },
            {
              path:'chineseBooks',
              element:<ChineseBooks />
            }
          ]
        },
      ],
    }
  ]);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值