@@ -602,39 +604,60 @@ export default new Template({}, ({ http, args }) => {
const observer = new IntersectionObserver(
(entries) => {
- if (isClickScrolling.current) return;
+ if (!isMounted) return;
+
+ const container = document.querySelector("#main-content");
+ const contentBox = document.querySelector(".prose");
+
+ if (!container || !contentBox) return;
- entries.forEach((entry) => {
- if (entry.isIntersecting) {
- setActiveId(entry.target.id);
- }
- });
+ // 找出所有进入可视区域的标题
+ const intersectingEntries = entries.filter(entry => entry.isIntersecting);
+
+ if (intersectingEntries.length > 0) {
+ // 获取所有可见标题的位置信息
+ const visibleHeadings = intersectingEntries.map(entry => ({
+ id: entry.target.id,
+ top: entry.boundingClientRect.top
+ }));
+
+ // 选择最靠近视口顶部的标题
+ const closestHeading = visibleHeadings.reduce((prev, current) => {
+ return Math.abs(current.top) < Math.abs(prev.top) ? current : prev;
+ });
+
+ setActiveId(closestHeading.id);
+ }
},
{
- root: containerRef.current,
- rootMargin: '-80px 0px -80% 0px',
- threshold: 0.5
+ root: document.querySelector("#main-content"),
+ rootMargin: '-20px 0px -80% 0px',
+ threshold: [0, 1]
}
);
- tocItems.forEach((item) => {
- const element = document.getElementById(item.id);
- if (element) {
- observer.observe(element);
- }
- });
-
- return () => {
+ if (isMounted) {
tocItems.forEach((item) => {
const element = document.getElementById(item.id);
if (element) {
- observer.unobserve(element);
+ observer.observe(element);
}
});
- };
- }, [tocItems]);
+ }
- // 修改点击��理函数
+ return () => {
+ if (isMounted) {
+ tocItems.forEach((item) => {
+ const element = document.getElementById(item.id);
+ if (element) {
+ observer.unobserve(element);
+ }
+ });
+ }
+ };
+ }, [tocItems, isMounted]);
+
+ // 修改点击处理函数
const handleTocClick = useCallback((e: React.MouseEvent, itemId: string) => {
e.preventDefault();
const element = document.getElementById(itemId);
@@ -644,6 +667,7 @@ export default new Template({}, ({ http, args }) => {
if (element && container && contentBox) {
isClickScrolling.current = true;
+ // 计算元素相对于内容容器的偏移量
const elementRect = element.getBoundingClientRect();
const contentBoxRect = contentBox.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
@@ -662,8 +686,6 @@ export default new Template({}, ({ http, args }) => {
behavior: "smooth",
});
- setActiveId(itemId);
-
// 滚动完成后重置标记
const resetTimeout = setTimeout(() => {
isClickScrolling.current = false;
@@ -673,17 +695,19 @@ export default new Template({}, ({ http, args }) => {
}
}, []);
- // 修改��动端目录的渲染逻辑
- const mobileMenu = isMounted && (
+ // 修改移动端目录的渲染逻辑
+ const mobileMenu = (
<>
-
+ {isMounted && (
+
+ )}
- {showToc && (
+ {isMounted && showToc && (
setShowToc(false)}
@@ -761,11 +785,11 @@ export default new Template({}, ({ http, args }) => {
return (
- {mobileMenu}
+ {isMounted && mobileMenu}
{
>
{/* 文章主体 */}
-
+
{/* 头部 */}
{
- {/* 修改片样式 */}
+ {/* 封面图片 */}
{mockPost.coverImage && (
{
envPrefix: "VITE_",
build: {
rollupOptions: {
- output: {
- manualChunks: {
- three: ['three'],
- gsap: ['gsap']
- }
- }
+ // 移除 manualChunks 配置
},
- // 优化大型依赖的处理
- chunkSizeWarningLimit: 1000
+ chunkSizeWarningLimit: 1500
+ },
+ ssr: {
+ noExternal: ['three', '@react-three/fiber', '@react-three/drei', 'gsap']
}
};
});