生产管理系统前端 1.修复系统导航过长的问题 2.利用旧菜单交互 开发菜单与导航

This commit is contained in:
2025-10-22 15:18:36 +08:00
parent 9afc680833
commit 7a21043dd8
25 changed files with 1843 additions and 109 deletions

View File

@@ -0,0 +1,101 @@
import { useEffect, useRef, useState, useCallback } from 'react';
import { useLayoutStore } from '@/stores/useLayoutStore';
interface UseElementHeightOptions {
onUpdate?: (height: number) => void;
immediate?: boolean; // 是否立即计算
}
export const useElementHeight = (options: UseElementHeightOptions = {}) => {
const elementRef = useRef<HTMLElement>(null);
const [isClient, setIsClient] = useState(false);
const { setNavigatorHeight } = useLayoutStore();
const lastHeightRef = useRef<number>(0);
// 确保在客户端执行
useEffect(() => {
setIsClient(true);
}, []);
// 使用 useCallback 来避免无限循环
const calculateHeight = useCallback(() => {
if (!elementRef.current || !isClient) return 0;
const height = elementRef.current.offsetHeight;
// 只有当高度真正发生变化时才更新
if (Math.abs(height - lastHeightRef.current) > 1) { // 允许1px的误差避免微小变化
lastHeightRef.current = height;
setNavigatorHeight(height);
// 调用自定义回调
if (options.onUpdate) {
options.onUpdate(height);
}
}
return height;
}, [isClient, setNavigatorHeight, options.onUpdate]);
// 手动更新高度的函数
const updateHeight = useCallback(() => {
return calculateHeight();
}, [calculateHeight]);
useEffect(() => {
if (!isClient) return;
const element = elementRef.current;
if (!element) return;
// 立即计算一次(如果需要)
if (options.immediate) {
// 使用 setTimeout 来避免在渲染过程中立即调用
setTimeout(() => {
calculateHeight();
}, 0);
}
// 使用防抖来优化性能
let debounceTimer: NodeJS.Timeout;
const debouncedCalculateHeight = () => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(calculateHeight, 100); // 100ms 防抖
};
// 创建 ResizeObserver 来监听元素大小变化
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
const { height } = entry.contentRect;
if (Math.abs(height - lastHeightRef.current) > 1) {
debouncedCalculateHeight();
}
}
});
// 开始观察元素
resizeObserver.observe(element);
// 监听窗口大小变化
const handleResize = () => {
debouncedCalculateHeight();
};
window.addEventListener('resize', handleResize, { passive: true });
window.addEventListener('orientationchange', handleResize, { passive: true });
// 清理函数
return () => {
resizeObserver.disconnect();
window.removeEventListener('resize', handleResize);
window.removeEventListener('orientationchange', handleResize);
clearTimeout(debounceTimer);
};
}, [isClient, calculateHeight, options.immediate]);
return {
elementRef,
updateHeight,
isClient,
};
};

View File

@@ -0,0 +1,57 @@
import { useEffect, useState } from 'react';
import { useLayoutStore } from '@/stores/useLayoutStore';
export const useViewHeight = () => {
const { setViewHeight, calculateMainBodyHeight } = useLayoutStore();
const [isClient, setIsClient] = useState(false);
// 确保在客户端执行
useEffect(() => {
setIsClient(true);
}, []);
const getViewHeight = () => {
if (!isClient) return 0;
// 获取视口高度
const height = window.innerHeight || document.documentElement.clientHeight;
return height;
};
useEffect(() => {
if (!isClient) return;
// 立即计算一次
const initialHeight = getViewHeight();
setViewHeight(initialHeight);
// 监听窗口大小变化
const handleResize = () => {
const newHeight = getViewHeight();
setViewHeight(newHeight);
};
// 监听方向变化
const handleOrientationChange = () => {
// 方向变化时稍微延迟计算,确保浏览器已经完成调整
setTimeout(() => {
const newHeight = getViewHeight();
setViewHeight(newHeight);
}, 100);
};
window.addEventListener('resize', handleResize, { passive: true });
window.addEventListener('orientationchange', handleOrientationChange, { passive: true });
// 清理函数
return () => {
window.removeEventListener('resize', handleResize);
window.removeEventListener('orientationchange', handleOrientationChange);
};
}, [isClient, setViewHeight]);
return {
getViewHeight,
isClient,
};
};