포스트 글이 길거나 블로그, 프로젝트 갯 수가 많아지면 스크롤이 발생해 상단 이동 버튼을 배치하는게 좋을 것 같아 추가해보았다.
상단 이동 버튼
window.scrollTo(xpos, ypos, behavior:'auto'}) 를 사용하면 원하는 위치로 이동 시킬 수 있다.
behavior의 값에는 auto, instant, smooth가 있다. (문자이므로 따옴표가 필요하다.)
auto는 기본 값이며, 바로 위치로 이동한다. instant도 같은 동작을 한다.
smooth는 부드럽게 이동하는 애니메이션 효과를 보여준다.
⇒ 부드럽게 상단 위치하기 위해서 클릭 시 window.scrollTo({ top: 0, behavior: "smooth" }); 실행되게 했다.
import { useEffect, useState } from "react"; import { HiChevronUp } from "react-icons/hi"; export default function MoveToTop() { const moveToTop = () => { window.scrollTo({ top: 0, behavior: "smooth" }); }; return ( <div onClick={moveToTop} className="fixed bottom-7 right-4 lg:right-10 p-2 z-20 cursor-pointer hover:scale-90 transition-all duration-500 rounded-full bg-[#2c82f2]" > <HiChevronUp className="text-2xl text-white" /> </div> ); }
상단 이동 버튼 + 일정 스크롤 높이에서 등장
추가로 스크롤 브라우저 최 상단에서는 상단 이동 버튼이 필요 없기 때문에 일정 스크롤 높이에서 부터 상단 이동 버튼이 등장했으면 좋을 것 같았다.
useState 를 활용해 버튼의 상태 값을 css에 적용했다.
showTopBtn ? "opacity-100 visible" : "opacity-0 invisible" showTopBtn가 true면 보이게 적용했다.
*visible 는 visibility: visible; / invisible 는 visibility: hidden; (tailwind 표기)
이제 필요한 거는 원하는 시점에서 showTopBtn가 true로 변하게 해야 됩니다.
useEffect(() => { const showBtnClick = () => { if (window.scrollY > 400) { setShowTopBtn(true); } else { setShowTopBtn(false); } }; window.addEventListener("scroll", showBtnClick); return () => { window.removeEventListener("scroll", showBtnClick); }; }, []);
전체 코드
import { cls } from "libs/utils"; import { useEffect, useState } from "react"; import { HiChevronUp } from "react-icons/hi"; export default function MoveToTop() { const [showTopBtn, setShowTopBtn] = useState(false); const moveToTop = () => { window.scrollTo({ top: 0, behavior: "smooth" }); }; useEffect(() => { const showBtnClick = () => { if (window.scrollY > 400) { setShowTopBtn(true); } else { setShowTopBtn(false); } }; window.addEventListener("scroll", showBtnClick); return () => { window.removeEventListener("scroll", showBtnClick); }; }, []); return ( <div onClick={moveToTop} className={cls( showTopBtn ? "opacity-100 visible" : "opacity-0 invisible", "fixed bottom-7 right-4 lg:right-10 p-2 z-20 cursor-pointer hover:scale-90 transition-all duration-500 rounded-full bg-[#2c82f2]" )} > <HiChevronUp className="text-2xl text-white" /> </div> ); }
추가 (2023.12.02)
특정 영역 안에서 상단 이동
다른 프로젝트에서 탭이 있는 모달 창을 만들던 중 스크롤이 생기는 모달이어서 탭 클릭 시 자동으로 위에서 부터 다시 시작하게 만들어야 했다.
DOM요소에 접근하기 위해 사용되는 React Hook 인 useRef 를 활용하여 해당 영역을 참조한다.
아래 코드에서는 참조된 영역의 scrollTop이 0이 아니면 수직 스크롤 바의 위치를 0으로 변경한다.
import { useState, useEffect, useRef } from "react"; export default function Ex() { const [modalTab, setModalTab] = useState(1); const modalInfoModal = useRef<HTMLDivElement>(null); const selectModalTabHandler = (order: number) => { setModalTab(order); if (modalInfoModal.current.scrollTop !== 0) { // 상단으로 이동 modalInfoModal.current.scrollTop = 0; } }; return ( <Modal> <ul> <li onClick={() => selectModalTabHandler(1)} className={modalTab === 1 ? "on" : ""} > 탭 1 </li> <li onClick={() => selectModalTabHandler(2)} className={modalTab === 2 ? "on" : ""} > 탭 2 </li> </ul> <div ref={modalInfoModal} > {modalTab === 1 ? ( <div className="topRank"> 탭 1 content</div> ) : ( <div className="topRank"> 탭 2 content</div> )} </div> <Modal/> ) }