dm_new menu
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
"use client";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
export function useScrollSpy(sectionIds: string[], options?: IntersectionObserverInit) {
|
||||
const [activeId, setActiveId] = useState(sectionIds[0] ?? "");
|
||||
const ratiosRef = useRef<Map<string, number>>(new Map());
|
||||
|
||||
useEffect(() => {
|
||||
const els = sectionIds
|
||||
.map((id) => document.getElementById(id))
|
||||
.filter(Boolean) as HTMLElement[];
|
||||
|
||||
if (!els.length) return;
|
||||
|
||||
const DEFAULT_ROOT_MARGIN = "83px 0px -65% 0px";
|
||||
|
||||
// 초기값 세팅(안정화)
|
||||
ratiosRef.current.clear();
|
||||
els.forEach((el) => ratiosRef.current.set(el.id, 0));
|
||||
|
||||
const io = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const e of entries) {
|
||||
const id = (e.target as HTMLElement).id;
|
||||
ratiosRef.current.set(id, e.isIntersecting ? e.intersectionRatio : 0);
|
||||
}
|
||||
|
||||
// ✅ 전체 섹션 중 가장 ratio 큰 항목을 active로
|
||||
let bestId = activeId;
|
||||
let bestRatio = -1;
|
||||
|
||||
for (const [id, ratio] of ratiosRef.current.entries()) {
|
||||
if (ratio > bestRatio) {
|
||||
bestRatio = ratio;
|
||||
bestId = id;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestId) setActiveId(bestId);
|
||||
},
|
||||
{
|
||||
root: null,
|
||||
threshold: [0, 0.01, 0.1, 0.25, 0.5, 0.75],
|
||||
rootMargin: DEFAULT_ROOT_MARGIN,
|
||||
...options,
|
||||
}
|
||||
);
|
||||
|
||||
els.forEach((el) => io.observe(el));
|
||||
return () => io.disconnect();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [sectionIds.join("|"), options?.rootMargin, JSON.stringify(options?.threshold)]);
|
||||
|
||||
return activeId;
|
||||
}
|
||||
Reference in New Issue
Block a user