react umi/max 封装页签组件

这篇具有很好参考价值的文章主要介绍了react umi/max 封装页签组件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

思路:封装一个页签组件,包裹页面组件,页面渲染之后把数据缓存到全局状态实现页面缓存。

浏览本博客之前先看一下我的博客实现的功能是否满足需求,实现功能:

- 页面缓存
- 关闭当前页
- 鼠标右键>关闭当前
- 鼠标右键>关闭其他
- 鼠标右键>关闭左侧
- 鼠标右键>关闭右侧
- 鼠标右键>全部关闭(默认跳转到首页)

如果您需要实现刷新页签功能,建议react umi/max 页签(react-activation)-CSDN博客

1. models/tabs

// 全局共享数据示例
import { useState } from 'react';

const useUser = () => {
  const [items, setItems] = useState<any[]>([]);  // 页签的全局Item数据
  const [key, setKey] = useState<string>('/home');  // 页签的高亮Key

  return {
    items,
    setItems,
    key,
    setKey,
  };
};

export default useUser;

2. components/PageHeadTabs

import { Home } from '@/pages/Home';
import { useLocation, useModel, useRouteProps } from '@umijs/max';
import { Dropdown, Tabs } from 'antd';
import { useEffect } from 'react';

type PageHeadTabsProps = {
  children: any;
};

const PageHeadTabs = (props: PageHeadTabsProps) => {
  const { name } = useRouteProps(); //获取当前路由名称
  const { children } = props; // Props获取元素、页面名称
  const { items, setItems, key, setKey } = useModel('tabs'); // 获取全局Item和Key
  const { pathname } = useLocation(); // 获取当前页的Pathname

  // 页签点击事件
  const onTabClick = (value: any) => {
    setKey(value); // 设置高亮的Key
    history.replaceState(null, '', value); // 拼接URL路径、但不执行跳转
  };

  // 关闭页签
  const onEdit = (targetKey: any, action: 'add' | 'remove') => {
    if (action === 'remove') {
      let newActiveKey = key;
      const lastIndex = items.findIndex((item) => item.key === targetKey);
      const newPanes = items.filter((item) => item.key !== targetKey);

      if (newPanes.length && newActiveKey === targetKey) {
        if (lastIndex - 1 >= 0) {
          newActiveKey = newPanes[lastIndex - 1].key;
        } else {
          newActiveKey = newPanes[0].key;
        }
      }

      setItems(newPanes);
      setKey(newActiveKey);
      history.replaceState(null, '', newActiveKey);
    }
  };

  // 关闭当前页
  const onCurrent = (e: any) => {
    e.domEvent.stopPropagation();

    let targetKey = JSON.parse(e?.key).name;
    let newActiveKey = key;
    const lastIndex = items.findIndex((item) => item.key === targetKey);
    const newPanes = items.filter((item) => item.key !== targetKey);

    if (newPanes.length && newActiveKey === targetKey) {
      if (lastIndex - 1 >= 0) {
        newActiveKey = newPanes[lastIndex - 1].key;
      } else {
        newActiveKey = newPanes[0].key;
      }
    }

    setItems(newPanes);
    setKey(newActiveKey);
    history.replaceState(null, '', newActiveKey);
  };

  // 关闭其他
  const onOther = (e: any) => {
    e.domEvent.stopPropagation();

    let targetKey = JSON.parse(e?.key).name;
    const newPanes = items.filter(
      (item) => item.key === targetKey || item.key === '/home',
    );

    setItems(newPanes);
    setKey(targetKey);
    history.replaceState(null, '', targetKey);
  };

  //关闭左侧
  const onLeft = (e: any) => {
    e.domEvent.stopPropagation();

    let targetKey = JSON.parse(e?.key).name;
    const lastIndex = items.findIndex((item) => item.key === targetKey);
    const newPanes = items
      .splice(0, lastIndex + 1)
      .filter((item) => item.key === targetKey || item.key === '/home');
    const oldIndex = newPanes.findIndex((item) => item.key === key);

    setItems(newPanes);
    if (oldIndex) {
      setKey(targetKey);
      history.replaceState(null, '', targetKey);
    }
  };

  // 关闭右侧
  const onRight = (e: any) => {
    e.domEvent.stopPropagation();
    let targetKey = JSON.parse(e?.key).name;
    const lastIndex = items.findIndex((item) => item.key === targetKey);
    const newPanes = items.splice(0, lastIndex + 1);
    const oldIndex = newPanes.findIndex((item) => item.key === key);

    setItems(newPanes);
    if (oldIndex) {
      setKey(targetKey);
      history.replaceState(null, '', targetKey);
    }
  };

  // 关闭全部
  const onAll = (e: any) => {
    e.domEvent.stopPropagation();

    const newPanes = items.splice(0, 1);

    setItems(newPanes);
    setKey('/home');
    history.replaceState(null, '', '/home');
  };

  const labelDropdown = (name: string, label: string) => {
    const lastIndex = items.findIndex((item) => item.key === name);
    return (
      <Dropdown
        menu={{
          items: [
            {
              label: '关闭当前',
              key: JSON.stringify({ name, key: 'current' }),
              disabled: name === '/home',
              onClick: onCurrent,
            },
            {
              label: '关闭其他',
              key: JSON.stringify({ name, key: 'other' }),
              disabled:
                (name === '/home' && items.length <= 1) ||
                (name !== '/home' && items.length <= 2),
              onClick: onOther,
            },
            {
              label: '关闭左侧',
              key: JSON.stringify({ name, key: 'left' }),
              disabled: lastIndex < 2,
              onClick: onLeft,
            },
            {
              label: '关闭右侧',
              key: JSON.stringify({ name, key: 'right' }),
              disabled:
                (name === '/home' && items.length <= 1) ||
                (name !== '/home' && items.length - lastIndex < 2),
              onClick: onRight,
            },
            {
              label: '全部关闭',
              key: JSON.stringify({ name, key: 'all' }),
              onClick: onAll,
              disabled: name === '/home' && items.length <= 1,
            },
          ],
        }}
        trigger={['contextMenu']}
      >
        <span>{label}</span>
      </Dropdown>
    );
  };

  useEffect(() => {
    const index = !items.find(({ key }) => key === pathname);
    const indexHome = !items.find(({ key }) => key === '/home');
    // 如果用户部署从主页进入,引入主页组件作为默认页签
    if (indexHome && pathname !== '/home') {
      const arr = {
        key: '/home',
        label: '首页',
        title: '首页',
        closable: false,
        children: <Home />,
      };
      setItems((item) => item?.concat([arr]));
    }
    // 添加当前页面到页签
    if (index) {
      const arr = {
        key: pathname,
        label: name,
        title: name,
        closable: pathname !== '/home',
        children: children,
      };
      setItems((item) => item?.concat([arr]));
    }
    setKey(pathname);
  }, []);

  useEffect(() => {
    // 页签长度发生变化时,塞入、更新所有标签右键下拉菜单
    setItems((items) =>
      items.map((item) => {
        return { ...item, label: labelDropdown(item.key, item.title) };
      }),
    );
  }, [items.length]);

  return (
    <Tabs
      hideAdd
      size="small"
      type="editable-card"
      activeKey={key}
      onEdit={onEdit}
      onTabClick={onTabClick}
      items={items}
    />
  );
};
export default PageHeadTabs;

3. pages/Home

import PageHeadTabs from '@/components/PageHeadTabs';
import React from 'react';

// *因为首页是默认页面所以有两种进入方式
// *第一种是通过/home进入,正常加载HomePage;
// *第二种是通过其他页面进入,加载Home即可。

export const Home: React.FC = () => {
  return <div>Home</div>;
};

const HomePage: React.FC = () => {
  return (
    <PageHeadTabs title="首页">
      <Home />
    </PageHeadTabs>
  );
};

export default HomePage;

4. 其他页面 

import PageHeadTabs from '@/components/PageHeadTabs';
import { Button } from 'antd';

// *除了Home页面,其他的包裹一层PageHeadTabs即可实现。

const AccessPage: React.FC = () => {

  return (
    <PageHeadTabs title="权限演示">
        <Button>按钮</Button>
    </PageHeadTabs>
  );
};

export default AccessPage;

5. 效果 

react umi/max 封装页签组件,新人必备,react.js,javascript,前端

自己临时封装的一个小组件,功能如上图。

缺点:没有刷新和拖拽功能。

优点:可以缓存页面。 文章来源地址https://www.toymoban.com/news/detail-801184.html

到了这里,关于react umi/max 封装页签组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 组件化开发之如何封装组件-react

    组件是构建用户界面的基本单元,它是一个独立的、可重用的、可组合的代码单元,用于表示UI的一部分。 人话:当谈论组件时,就像在搭积木一样,每个组件都是一个 独立的、可以重复使用 的代码块,用来构建网页或应用的各个部分。比如界面的布局,像按钮、文本输入

    2024年02月11日
    浏览(51)
  • jQuery.js - 前端必备的Javascript库

    作者: WangMin 格言: 努力做好自己喜欢的每一件事 jQuery.js 是什么? jQuery是一个快速简洁、免费开源易用的JavaScript框架, 倡导写更少的代码,做更多的事情 。它封装JavaScript常用的功能代码,提供了一种简便的JavaScript设计模式,以及我们开发中常用到的操作DOM的API,优化HTML文

    2024年02月05日
    浏览(50)
  • React组件封装:文字、表情评论框

    1.需求描述 根据项目需求,采用Antd组件库需要封装一个评论框,具有以下功能: 支持文字输入 支持常用表情包选择 支持发布评论 支持自定义表情包 2.封装代码  ./InputComment.tsx ./util.ts  ./index.less    3.问题解决 同一页面有多个评论框时,光标位置不准确?答:从组件外部传

    2024年04月08日
    浏览(98)
  • react使用hook封装一个tab组件

    2024年02月09日
    浏览(37)
  • 前端(十五)——开源一个用react封装的图片预览组件

    👵博主:小猫娃来啦 👵文章核心:开源一个react封装的图片预览组件 Gitee:点此跳转下载 CSDN:点此跳转下载 装依赖 运行 打开 创建一个React函数组件并命名为 ImageGallery 。 在组件内部,使用useState钩子来定义状态变量,并初始化为合适的初始值。 selectedImageUrl 来追踪当前选

    2024年02月10日
    浏览(48)
  • React + Typescript + Antd:封装通用的字典组件DXSelect

    在开发中,我们经常遇到这样的场景,在表单中,有个下拉框,选择对应的数据。 那么这个下拉框的选项,就是字典。一搬的做法是,通过antd的Select来实现,代码如下:

    2024年02月15日
    浏览(66)
  • react Hook+antd封装一个优雅的弹窗组件

    前言 在之前学vue2的时候封装过一个全局的弹窗组件,可以全局任意地方通过this调用,这次大创项目是用react技术栈,看了一下项目需求,突然发现弹窗还是比较多的,主要分为基础的弹窗以及form表单式的弹窗,如果只是无脑的去写代码,那些项目也没啥必要了。正好react和

    2024年02月13日
    浏览(31)
  • 封装React组件DragLine,鼠标拖拽的边框改变元素宽度

    原文合集地址如下,有需要的朋友可以关注 本文地址 合集地址 在项目中,设计说想做个面板,其宽度随鼠标拖拽而变化,有最大最小值。基于这个小功能封装一个可拖拽组件,在需要的地方引入即可。 这里只是实现x方向的拖拽,y轴拖拽思路差不多。 既然是鼠标操作,那肯

    2024年02月16日
    浏览(31)
  • react 基于 dnd-kit 封装的拖拽排序组件

    官网地址 https://docs.dndkit.com/introduction/installation 安装依赖 简单使用 建议直接看官网,已经描述得很详细了:https://docs.dndkit.com/presets/sortable 效果展示 注意事项 如果传入的是一个函数式组件,需要用一个html元素包裹住 这里的排序默认是读取 list 中的 id 作为 key 值的,如果

    2024年02月16日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包