react+anddesign组件Tabs实现后台管理系统自定义页签头

使用react和anddesign开发一个后台管理页签头。这里使用全局状态管理zustand来实现这个功能。

安装zustand

javascript 复制代码
npm install zustand --save

创建store文件夹并在文件夹下创建useTabs.ts文件

javascript 复制代码
// useTabs.ts
import { create } from 'zustand'

interface tabLiSTState {
  tabList: Array<any>, // 页签头数据
  setTabList: (tabs: Array<any>) => void // 添加tabs全局方法
}

export const useTabs = create<tabLiSTState>((set) => ({
  tabList: [{ title: "首页", path: '/' }],
  setTabList: (tabs) => set({ tabList: tabs }),
}))

创建Tabs组件组件

使用useEffect监听路由的变化,路由变化调用添加页签方法把当前菜单名称title和路径添加到全局状态管理中

javascript 复制代码
import { useState, useEffect } from 'react'
import { Tabs } from 'antd'
import { useLocation, useNavigate } from 'react-router-dom'
import { routerArray } from '@/router/routes'
import MoreButton from './components/MoreButton'
import { useTabs } from '@/store/useTabs'
import './index.scss'
import { searchRoute } from '@/utils'
const LayoutTabs = () => {
  const { pathname } = useLocation()
  const navigate = useNavigate();
  const [activeTabs, setActiveTabs] = useState(pathname)
  const { tabList, setTabList } = useTabs()
  // 监听路由变化
  useEffect(() => {
    addTabs()
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [pathname])
  const clickTabs = (path: string) => {
    navigate(path)
  }
  // 添加tabs
  const addTabs = () => {
    const route = searchRoute(pathname, routerArray)
    const newTabList = JSON.parse(JSON.stringify(tabList))
    if(tabList.every(item => item.path !== pathname)) {
      newTabList.push({
        title: route.meta!.title,
        path: route.path,
      })
    }
    setTabList(newTabList)
    setActiveTabs(pathname)
  }
  // 关闭tabs
  const closeTabs = (path) => {
    if(path === '/') return
    if(pathname === path) {
      tabList.forEach((item, index) => {
        if(item.path !== path) return
        const nextTab = tabList[index + 1] || tabList[index - 1]
        if(!nextTab) return
        navigate(nextTab.path)
      }) 
    }
    setTabList(tabList.filter(item => item.path !== path))
  }
  const item = tabList.map((i) =>{
    return {
      label: i.title,
      key: i.path,
      closable: i.path !== '/'
    }
  })
  return (
    <div className='tabs'>
      <Tabs
        animated
        hideAdd
        type="editable-card"
        activeKey={activeTabs}
        onChange={clickTabs}
        onEdit={closeTabs}
        items={item}
      />
      <MoreButton tabList={tabList} closeTabs={closeTabs} setTabList={setTabList} />
    </div>
  )
}

更多操作

主要是一些重新加载、关闭当前标签页、关闭左侧、关闭右侧、关闭其它、关闭所有

MoreButton组件

javascript 复制代码
import { DownOutlined } from '@ant-design/icons';
import { useLocation, useNavigate } from 'react-router-dom'
import { Dropdown } from 'antd';

const MoreButton = (props) => {
  const { pathname } = useLocation()
  const navigate = useNavigate();

  // 关闭左侧
  const closeLeftTabs = () => {
    const activeIndex = props.tabList.findIndex(item => item.path === pathname)
    const newTabs = props.tabList.filter((_, index) => index >= activeIndex || _.path === '/')
    props.setTabList(newTabs)
  }
  // 关闭右侧
  const closeRightTabs = () => {
    const activeIndex = props.tabList.findIndex(item => item.path === pathname)
    const newTabs = props.tabList.filter((_, index) => index <= activeIndex)
    props.setTabList(newTabs)
  }
  // 关闭其它
  const closeOtherTabs = () => {
    const list = props.tabList.filter(item => item.path === pathname || item.path === '/')
    props.setTabList(list)
  }
  // 关闭所有
  const closeAllTabs = () => {
    const list = props.tabList.filter(item => item.path === '/')
    props.setTabList(list)
    navigate('/')
  }
  const items = [
    {
      key: '1',
      label: '重新加载',
      onClick: () => {
        window.location.reload();
      }
    },
    {
      key: '2',
      label: '关闭当前',
      onClick: () => {
        return props.closeTabs(pathname)
      }
    },
    {
      key: '3',
      label: '关闭左侧',
      onClick: closeLeftTabs
    },
    {
      key: '4',
      label: '关闭右侧',
      onClick: closeRightTabs
    },
    {
      key: '5',
      label: '关闭其它',
      onClick: closeOtherTabs
    },
    {
      key: '6',
      label: '关闭所有',
      onClick: closeAllTabs
    },
  ];
  return (
    <Dropdown.Button
      className='moreButton'
      icon={<DownOutlined />}
      menu={{ items }}
      type="primary"
    >
      更多
    </Dropdown.Button>
  );
}

export default MoreButton;
相关推荐
一次旅行17 分钟前
多智能体编排实战:拆解Plan-and-Execute范式+三层记忆架构,手写无依赖轻量Agent调度引擎
前端·javascript·架构
小玮看世界1 小时前
[Python]从“脏”数据到优雅实现:一个IoT滑动窗口最大值问题的测试驱动优化实录
linux·前端·python
尤乐娃子2 小时前
进入大厂(厂子大)实习Day11
前端·笔记·实习
xiaoxiangsiyan2 小时前
运维之前端反调试学习
运维·前端·学习·状态模式
小徐_23332 小时前
TRAE WORK 实战,之前写一篇水文要半天,现在用 TRAE Work 摸鱼2分钟交差,真香!
前端·trae
明月_清风2 小时前
🤗 Hugging Face 模型上传完全指南:从本地到 Hub 的 4 种姿势
前端·后端·ai编程
sugar__salt2 小时前
跟着 Demo 学 Pinia:两种仓库写法 + 完整 TodoList 复现
前端·javascript·vue.js·前端框架·vue
To_OC3 小时前
从一个名字编辑组件开始,我把 React + TS 的数据流和副作用彻底搞明白了
前端·react.js·typescript
程序员黑豆4 小时前
Java入门第一步:从零开始编写你的第一个Hello World程序
java·前端·ai编程