前言
看了前端小付的文章手把手带你实现一个多页签umi插件,自己动手实现了一个umi插件(用了好久umi竟然没写过umi插件😓)。这款插件加入了一些新功能(小付在其他文章实现过的),也解决了一些问题(我称之为 Tab幽灵问题),现在把它发布出来(然后水文章)。
介绍
特点
- 可拖拽tabs
- 选择”关闭其他“时,自动跳转,避免空白页
- 不使用国际化插件
安装
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>
);
}
总结
交了个作业,写了一篇水文分享。最后推荐关注前端大佬前端小付。