index.jsx 5 KB
/* eslint-disable react/jsx-key */
import React, { useState, useEffect, useRef, memo } from 'react';
import { RouteContext } from '@ant-design/pro-layout';
import { history } from '@umijs/max';
import Tags from './Tags';
import styles from './index.less';
import { Scrollbars } from 'react-custom-scrollbars';
// tree遍历
function treeForeach(tree, func) {
  tree.forEach((data) => {
    func(data);
    data.children && treeForeach(data.children, func); // 遍历子树
  });
}

const TagView = ({ children, home }) => {
  const [tagList, setTagList] = useState([]);

  const [currentPath, setCurrentPath] = useState();
  const routeContextRef = useRef();

  useEffect(() => {
    if (routeContextRef.current) {
      handleOnChange(routeContextRef.current);
    }
  }, [routeContextRef.current]);

  // 初始化 visitedViews,设置首页
  const initTags = (routeContext) => {
    // console.log(routeContext);
    const { menuData } = routeContext;
    if (tagList.length === 0 && menuData) {
      const allarr = [];
      treeForeach(menuData, (node) => {
        allarr.push(node);
      });
      const firstTag = allarr.filter((el) => el.path === location?.hash?.replace('#', ''))[0];
      if (firstTag) {
        const title = firstTag.name;
        const path = firstTag.path;
        history.push({ pathname: firstTag.path, query: firstTag.query });
        setTagList([
          {
            title,
            path,
            children: firstTag.element,
            refresh: 0,
            active: true,
            key: firstTag.key,
          },
        ]);
      }
    }
  };

  // 监听路由改变
  const handleOnChange = (routeContext) => {
    const { currentMenu } = routeContext;
    // console.log(tagList);
    // tags初始化
    if (tagList.length === 0) {
      return initTags(routeContext);
    }
    // 判断是否已打开过该页面
    let hasOpen = false;
    if (currentMenu.path) {
      const tagsCopy = tagList.map((item) => {
        if (currentMenu?.path === item.path) {
          //console.log(item);
          hasOpen = true;
          // 刷新浏览器时,重新覆盖当前 path 的 children
          // console.log(item);
          return { ...item, active: true, children: item.children };
        } else {
          return { ...item, active: false };
        }
      });

      // 没有该tag时追加一个,并打开这个tag页面
      if (!hasOpen) {
        const title = routeContext.title || '';
        const path = currentMenu?.path;
        tagsCopy.push({
          title,
          path,
          children,
          refresh: 0,
          active: true,
        });
      }

      return setTagList(tagsCopy);
    }
  };

  // 关闭标签
  const handleCloseTag = (tag) => {
    const tagsCopy = tagList.map((el, i) => ({ ...el }));

    // 判断关闭标签是否处于打开状态
    tagList.forEach?.((el, i) => {
      if (el.path === tag.path && tag.active) {
        const next = tagList[i - 1];
        next.active = true;
        history.push({ pathname: next?.path, query: next?.query });
      }
    });

    setTagList(tagsCopy.filter((el) => el.path !== tag?.path));
  };

  // 关闭所有标签
  const handleCloseAll = () => {
    const tagsCopy = tagList.filter((el) => el.path === home);
    history.push(home);
    setTagList(tagsCopy);
  };

  // 关闭其他标签
  const handleCloseOther = (tag) => {
    const tagsCopy = tagList.filter((el) => el.path === home || el.path === tag.path);
    history.push({ pathname: tag?.path, query: tag?.query });
    setTagList(tagsCopy);
  };

  const [refresh, setrefresh] = useState(true);
  // 刷新选择的标签
  const handleRefreshTag = async (tag) => {
    // const tagsCopy = tagList.map((item) => {
    //   if (item.path === tag.path) {
    //     history.push({ pathname: tag?.path, query: tag?.query });
    //     return { ...item, refresh: item.refresh + 1, active: true };
    //   }
    //   return { ...item, active: false };
    // });
    // setTagList(tagsCopy);
    await setrefresh(false);
    setrefresh(true);
  };

  return (
    <>
      <RouteContext.Consumer>
        {(value) => {
          setTimeout(() => {
            setCurrentPath(value.currentMenu?.path);
          }, 0);
          routeContextRef.current = value;
          return null;
        }}
      </RouteContext.Consumer>
      <div className={styles.tag_view}>
        <div className={styles.tags_container}>
          <Tags
            tagList={tagList}
            closeTag={handleCloseTag}
            closeAllTag={handleCloseAll}
            closeOtherTag={handleCloseOther}
            refreshTag={handleRefreshTag}
            home={home}
          />
        </div>
      </div>
      <div className={styles.child}>
        <div className={styles.contianbox}>
          <Scrollbars
            thumbMinSize={10}
            autoHide
            style={{ width: '100%', height: '100%' }}
            hideTracksWhenNotNeeded={true}
          >
            {refresh && children}
          </Scrollbars>
        </div>
      </div>
    </>
  );
};

export default TagView;