交作业!一个多页签umi插件

304 阅读1分钟

前言

看了前端小付的文章手把手带你实现一个多页签umi插件,自己动手实现了一个umi插件(用了好久umi竟然没写过umi插件😓)。这款插件加入了一些新功能(小付在其他文章实现过的),也解决了一些问题(我称之为 Tab幽灵问题),现在把它发布出来(然后水文章)。

介绍

特点

  1. 可拖拽tabs
  2. 选择”关闭其他“时,自动跳转,避免空白页
  3. 不使用国际化插件

安装

pnpm i @huang1997/umi-plugin-keepalive-tabs

## 需要安装的依赖
pnpm add @dnd-kit/core @dnd-kit/modifiers @dnd-kit/sortable @dnd-kit/utilities

使用

Configure in .umirc.ts,

export default {
  plugins: [
    ['@huang1997/umi-plugin-keepalive-tabs'],
  ],
}

Tab幽灵问题

问题描述:对Tab栏拖拽排序完成后,此时删除一个Tab,会发现Tab栏的排序复原了。

问题原因:Tab栏本身依赖KeepAliveTabs数组,而拖拽Tab并不会同时修改KeepAliveTabs的排序,所以导致了Tab幽灵问题。

解决思路:我选择在DraggableTabs组件暴露出onItemsDragEnd事件,这个事件会在Tab栏拖拽完成时响应(即onDragEnd中响应),然后监听onItemsDragEnd事件,同步修改KeepAliveTabs的排序。

上代码:

const DraggableTabs: React.FC<
  TabsProps & { onItemsDragEnd?: (items: TabsProps['items']) => void }
> = ({ onItemsDragEnd, ...props }) => {
  // ...

  const onDragEnd = ({ active, over }: DragEndEvent) => {
    if (active.id !== over?.id) {
      setItems((prev) => {
        const activeIndex = prev.findIndex((i) => i.key === active.id);
        const overIndex = prev.findIndex((i) => i.key === over?.id);
        const tabs = arrayMove(prev, activeIndex, overIndex);
        
        // 这里响应onItemsDragEnd
        if (onItemsDragEnd) {
          onItemsDragEnd(tabs);
        }
        return tabs;
      });
    }
  };
  
  // ...
}

const KeepAliveLayout = () => {
    const onItemsDragEnd = useCallback((items: any[] | undefined) => {
    if (items && items.length > 0) {
       // 同步修改keepAliveTabs数组
      setKeepAliveTabs((tabs) => {
        return items.map((item) => {
          return tabs.find((tab) => tab.routePath === item.key);
        }) as Array<KeepAliveTab>;
      });
    }
  }, []);
  
  return (
    <KeepAliveTabContext.Provider value={keepAliveContextValue}>
      <DraggableTabs
        type="editable-card"
        items={tabItems}
        activeKey={activeTabRoutePath}
        onChange={onTabsChange}
        onItemsDragEnd={onItemsDragEnd}
        className="keep-alive-tabs"
        hideAdd
        animated={false}
        onEdit={onTabEdit}
      />
    </KeepAliveTabContext.Provider>
  );
}

总结

交了个作业,写了一篇水文分享。最后推荐关注前端大佬前端小付