前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >antd pro v5 tab标签卡(多标签页)实现

antd pro v5 tab标签卡(多标签页)实现

作者头像
星宇大前端
发布2022-05-06 17:26:10
5.3K1
发布2022-05-06 17:26:10
举报
文章被收录于专栏:大宇笔记

多标签页很多公司的后台管理系统都会有这个需求,之前用vue一般架子也是带的,现在公司用了antd pro ,看了下官方不支持,确实会影响性能,但是架不住需求。

背景


先看下远古截图:

在这里插入图片描述
在这里插入图片描述

https://github.com/ant-design/ant-design-pro/issues/220

17年提出的需求现在还没有实现,看样官方也是铁了心了。在看看提供的其他解决方案:

另外我还找到了一个插件也可以实现:

https://github.com/fangzhengjin/umi-plugin-panel-tabs

这些不是因为这版本不对,就是细节不满意决定自己实现一个版本。

自己实现的好处:

  • UI自定义
  • 功能添加方便,知道核心原理,修改Bug也方便。

核心原理


先看最后实现的版本:

请添加图片描述
请添加图片描述

核心问题:

  1. 菜单标签路由地址联动
  2. 标签卡内容需要缓存,切换不丢失
  3. 后台返回路由也应该支持

功能实现


核心实现思路:

  1. 通过地址栏变化匹配路由变化标签栏
  2. 标签卡选用Tabs组件+ Route 标签加key缓存
  3. dva来实现数据管理,也可以选用别的,能全局操作即可。

具体逻辑就是,写一个TabsView 组件,在Layout chlidren的时候嵌套上Tabs 多页签卡这一层。

Layout 文件夹Index.ts 文件:

代码语言:javascript
复制
<TabsView
            activeKey={getActiveKey(props.tagsModel)}
            tags={props.tagsModel}
            route={props.route}
            dispatch={props.dispatch}
          />

1、 数据实现组织

利用dva 来实现tags 数组的增删改查,具体代码如下:

代码语言:javascript
复制
/*
 * @Author: ZY
 * @Date: 2021-10-25 13:42:43
 * @LastEditors: ZY
 * @LastEditTime: 2022-05-01 10:18:48
 * @Description: dva tags
 * tabs 整理设计思路:
 * 需求:两种逻辑,一种是菜单功能,功能、路由、tag是一对一的关系,另一种单据类可以开多个
 * 设计:
 * 利用tabs 进行页面布局,来实现缓存的目的。key是path和query的合集,这样能满足需求
 * 利用dva组织数据
 * 动态加载组件,组件利用key关联
 */
import type { Reducer } from 'umi';
import _remove from 'lodash/remove';
import _cloneDeep from 'lodash/cloneDeep';
import _findIndex from 'lodash/findIndex';

export interface Tag {
  key: string;
  title: string;
  path?: string;
  active: boolean;
  query?: any;
}

export type TagsStateType = Tag[];

export interface TagsModelType {
  namespace: 'tagsModel';
  state: TagsStateType;
  reducers: {
    addTag: Reducer<TagsStateType>;
    updateActive: Reducer<TagsStateType>;
    removeTag: Reducer<TagsStateType>;
    removeAllTags: Reducer<TagsStateType>;
  };
}

/**
 * @description: 初始化tab
 * @param {*}
 * @return {*}
 */
const homeTag: Tag = {
  key: `/dashboard`,
  title: '首页',
  active: true,
  path: '/dashboard',
};

/**
 * @description:
 * @param {*}
 * @return {*}
 */
const addNewTag = (tags: Tag[], newTag: Tag) => {
  if (_findIndex(tags, (t) => t.key === newTag.key) === -1) {
    // tags数组里面有没有新增的tag
    const cTags = tags.map((t) => {
      const ct = _cloneDeep(t);
      ct.active = false;
      return ct;
    });
    return [...cTags, newTag];
  }

  // 新增tag 在数组中,选中即可。
  const cTags = tags.map((t) => {
    const ct = _cloneDeep(t);
    ct.active = ct.key === newTag.key;
    return ct;
  });
  return cTags;
};

const TagsModel: TagsModelType = {
  namespace: 'tagsModel',
  state: [homeTag] as TagsStateType,
  reducers: {
    addTag: (state, action) => {
      if (state) {
        return addNewTag(state, action.payload);
      }
      return [];
    },
    updateActive: (state, action) => {
      if (!state) {
        return [];
      }
      const cTags = state.map((t) => {
        const ct = _cloneDeep(t);
        ct.active = ct.key === action.payload;
        return ct;
      });
      return [...cTags];
    },
    removeTag: (state, action) => {
      if (!state) {
        return [];
      }
      const ct = _cloneDeep(state);
      if (ct.filter((t) => t.active)[0].key === action.payload) {
        _remove(ct, (tag: Tag) => tag.key === action.payload);
        // 如果关闭的是当前选中的标签,默认选中最后一个的策略
        ct[ct.length - 1].active = true;
      } else {
        _remove(ct, (tag: Tag) => tag.key === action.payload);
      }
      return [...ct];
    },
    removeAllTags: () => {
      return [];
    },
  },
};

export default TagsModel;

2、 tabsView 组件核心代码

这里会遍历tags 数组,然后创建tab, 每一个tab 都用Route 标签缓存,通过路径匹配的组件。

代码语言:javascript
复制
 <Tabs
        activeKey={activeKey}
        type="editable-card"
        hideAdd={true}
        onEdit={tabOnEdit}
        onChange={tabOnChange}
        onTabClick={onTabClick}
      >
        {tags.length &&
          tags.map((tag) => {
            return (
              <TabPane tab={tag.title} key={tag.key} closable={tag.key !== '/dashboard'}>
                <Route key={tag.key} component={getPathComponent(tag.path!)} exact />
              </TabPane>
            );
          })}
      </Tabs>

这样核心内容基本讲完,边缘代码就不多赘述了,代码再项目里还没来得及抽取,如有需要以后找时间发出。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 核心原理
  • 功能实现
    • 1、 数据实现组织
      • 2、 tabsView 组件核心代码
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档