특정 요소가 위치한 곳까지 스크롤을 이동하고 싶을 때 element.scrollIntoView
메서드를 이용하면 간편하게 구현할 수 있다. scrollIntoView
메서드는 총 3가지 방법으로 사용할 수 있다. (MDN)
element.scrollIntoView(align)
파라미터 없음 — element가 브라우저 화면 가장 위로 오도록 스크롤(정렬)
element.scrollIntoView() // element.scrollIntoView(true)와 동일
boolean 파라미터
element.scrollIntoView(true) // { block: "start", inline: "nearest" } 옵션과 동일
element.scrollIntoView(false) // { block: "end", inline: "nearest" } 옵션과 동일
true
를 넘겼을 때 : element가 브라우저 화면 가장 위로 오도록 스크롤(정렬)false
를 넘겼을 때 : element가 브라우저 화면 가장 아래로 오도록 스크롤(정렬)옵션 객체 파라미터
element.scrollIntoView({ behavior: "smooth", block: "end", inline: "nearest" });
<aside> <img src="/icons/search_gray.svg" alt="/icons/search_gray.svg" width="40px" /> block, inline 옵션값 설명
start : element가 브라우저 화면 가장 위로 오도록 스크롤(정렬)
end : element가 브라우저 화면 가장 아래로 오도록 스크롤(정렬)
center : element가 브라우저 화면 중간으로 오도록 스크롤(정렬)
nearest : element와 가까운 곳으로 스크롤 </aside>
behavior : 스크롤 전환 효과 (기본값 auto
)
auto
smooth
block : 수직 정렬 (기본값 start
)
start
end
center
nearest
inline : 수평 정렬 (기본값 nearest
)
start
end
center
nearest
const moveToTop = () => document.body.scrollIntoView(true); // 상단으로 이동
const moveToBottom = () => document.body.scrollIntoView(false); // 하단으로 이동
// 컴포넌트 본문 (배열 orders, Set 객체 selectedOrderIds를 prop으로 받음)
const tableRowRefs = useRef(
orders.map(({ order_id }) => ({
id: order_id,
element: createRef<HTMLTableRowElement>(), // ref 객체 여러개 생성
}))
);
useScrollIntoView({
isActive: selectedOrderIds.size === 1, // true 일때만 활성화
ref: tableRowRefs.current.find(({ id }) => id === [...selectedOrderIds][0])?.element,
align: { behavior: "smooth", block: "center" }, // align 옵션
});
return (
<div>
{orders.map((order, i, { length }) => (
<div ref={tableRowRefs.current[i].element}>{/* ... */}</div>
))}
</div>
);
interface Props {
isActive: boolean; // useScrollIntoView 훅 활성화 여부
ref: RefObject<HTMLElement> | undefined;
align?: ScrollIntoViewOptions; // scrollIntoView 메서드 align 옵션
}
/** 첫 렌더링에만 선택한 엘리먼트가 위치한 곳으로 스크롤하는 Hook */
export default function useScrollIntoView({ isActive, ref, align }: Props) {
const isNavigated = useRef(false); // 요소가 있는곳까지 스크롤 했는지 여부
useEffect(() => {
if (isActive && !isNavigated.current) {
ref?.current?.scrollIntoView(align);
isNavigated.current = true; // 첫 렌더링에만 스크롤하기 위해 isNavigated 값 true로 변경
}
}, [align, isActive, ref]);
}