feat(SubTabContainer): 支持 Tab 激活状态和刷新机制
- SubTabContainer: 新增 isActive 和 activationKey props 传递给子组件 - SubTabContainer: 修复 Tab 切换时页面滚动位置跳转问题 - TabPanelContainer: 新增 skeleton prop 支持自定义骨架屏 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -181,6 +181,11 @@ const SubTabContainer: React.FC<SubTabContainerProps> = memo(({
|
||||
() => new Set([controlledIndex ?? defaultIndex])
|
||||
);
|
||||
|
||||
// 记录每个 Tab 的激活次数(用于支持特定 Tab 切换时重新请求)
|
||||
const [activationCounts, setActivationCounts] = useState<Record<number, number>>(
|
||||
() => ({ [controlledIndex ?? defaultIndex]: 1 })
|
||||
);
|
||||
|
||||
// 合并主题
|
||||
const theme: SubTabTheme = {
|
||||
...THEME_PRESETS[themePreset],
|
||||
@@ -192,6 +197,9 @@ const SubTabContainer: React.FC<SubTabContainerProps> = memo(({
|
||||
*/
|
||||
const handleTabChange = useCallback(
|
||||
(newIndex: number) => {
|
||||
// 保存当前滚动位置,防止 Tab 切换时页面跳转
|
||||
const scrollY = window.scrollY;
|
||||
|
||||
const tabKey = tabs[newIndex]?.key || '';
|
||||
onTabChange?.(newIndex, tabKey);
|
||||
|
||||
@@ -201,9 +209,20 @@ const SubTabContainer: React.FC<SubTabContainerProps> = memo(({
|
||||
return new Set(prev).add(newIndex);
|
||||
});
|
||||
|
||||
// 更新激活计数(用于触发特定 Tab 的数据刷新)
|
||||
setActivationCounts(prev => ({
|
||||
...prev,
|
||||
[newIndex]: (prev[newIndex] || 0) + 1,
|
||||
}));
|
||||
|
||||
if (controlledIndex === undefined) {
|
||||
setInternalIndex(newIndex);
|
||||
}
|
||||
|
||||
// 恢复滚动位置,阻止浏览器自动滚动
|
||||
requestAnimationFrame(() => {
|
||||
window.scrollTo(0, scrollY);
|
||||
});
|
||||
},
|
||||
[tabs, onTabChange, controlledIndex]
|
||||
);
|
||||
@@ -343,6 +362,8 @@ const SubTabContainer: React.FC<SubTabContainerProps> = memo(({
|
||||
const Component = tab.component;
|
||||
// 懒加载:只渲染已访问过的 Tab
|
||||
const shouldRender = !isLazy || visitedTabs.has(idx);
|
||||
// 判断是否为当前激活的 Tab(用于控制数据加载)
|
||||
const isActive = idx === currentIndex;
|
||||
|
||||
return (
|
||||
<TabPanel key={tab.key} p={0}>
|
||||
@@ -361,7 +382,11 @@ const SubTabContainer: React.FC<SubTabContainerProps> = memo(({
|
||||
)
|
||||
}
|
||||
>
|
||||
<Component {...componentProps} />
|
||||
<Component
|
||||
{...componentProps}
|
||||
isActive={isActive}
|
||||
activationKey={activationCounts[idx] || 0}
|
||||
/>
|
||||
</Suspense>
|
||||
) : null}
|
||||
</TabPanel>
|
||||
|
||||
@@ -28,6 +28,8 @@ export interface TabPanelContainerProps {
|
||||
loadingMessage?: string;
|
||||
/** 加载状态高度 */
|
||||
loadingHeight?: string;
|
||||
/** 自定义骨架屏组件,优先于默认 Spinner */
|
||||
skeleton?: React.ReactNode;
|
||||
/** 子组件间距,默认 6 */
|
||||
spacing?: number;
|
||||
/** 内边距,默认 4 */
|
||||
@@ -74,6 +76,7 @@ const TabPanelContainer: React.FC<TabPanelContainerProps> = memo(
|
||||
loading = false,
|
||||
loadingMessage = '加载中...',
|
||||
loadingHeight = '200px',
|
||||
skeleton,
|
||||
spacing = 6,
|
||||
padding = 4,
|
||||
showDisclaimer = false,
|
||||
@@ -81,6 +84,10 @@ const TabPanelContainer: React.FC<TabPanelContainerProps> = memo(
|
||||
children,
|
||||
}) => {
|
||||
if (loading) {
|
||||
// 如果提供了自定义骨架屏,使用骨架屏;否则使用默认 Spinner
|
||||
if (skeleton) {
|
||||
return <>{skeleton}</>;
|
||||
}
|
||||
return <LoadingState message={loadingMessage} height={loadingHeight} />;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user