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;
相关推荐
GISer_Jing7 小时前
前端营销技术实战:数据+AI实战指南
前端·javascript·人工智能
GIS之路8 小时前
使用命令行工具 ogr2ogr 将 CSV 转换为 Shp 数据(二)
前端
嘉琪0018 小时前
Vue3+JS 高级前端面试题
开发语言·前端·javascript
vipbic9 小时前
用 Turborepo 打造 Strapi 插件开发的极速全栈体验
前端·javascript
天涯学馆9 小时前
为什么 JavaScript 可以单线程却能处理异步?
前端·javascript
Henry_Lau6179 小时前
主流IDE常用快捷键对照
前端·css·ide
陶甜也9 小时前
使用Blender进行现代建筑3D建模:前端开发者的跨界探索
前端·3d·blender
我命由我1234510 小时前
VSCode - Prettier 配置格式化的单行长度
开发语言·前端·ide·vscode·前端框架·编辑器·学习方法
HashTang10 小时前
【AI 编程实战】第 4 篇:一次完美 vs 五轮对话 - UnoCSS 配置的正确姿势
前端·uni-app·ai编程
JIngJaneIL10 小时前
基于java + vue校园快递物流管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js