🧭 λ„€λΉ„κ²Œμ΄μ…˜ λ°” κ΅¬ν˜„

박상은·2022λ…„ 8μ›” 9일
0

🧺 bleshop 🧺

λͺ©λ‘ 보기
1/10

Next.js와 tailwindcssλ₯Ό μ΄μš©ν•œ ν”„λ‘œμ νŠΈμž…λ‹ˆλ‹€.

πŸ“‘ ꡬ쑰 섀계

λ„€λΉ„κ²Œμ΄μ…˜ λ°”λŠ” μ΅œν•˜λ‹¨μ— 뢙여놓도둝 λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.

μŠ€ν¬λ‘€μ„ λ‚΄λ¦¬λŠ” κ²½μš°μ—λŠ” ν˜„μž¬ νŽ˜μ΄μ§€μ˜ λ‚΄μš©μ„ μ½μ–΄λ³΄λŠ” 경우일 것이기 λ•Œλ¬Έμ— μ˜μ—­μ„ λ„“νžˆκΈ° μœ„ν•΄μ„œ λ„€μ΄κ²Œμ΄μ…˜ λ°”λ₯Ό 숨기고, μŠ€ν¬λ‘€μ„ μ˜¬λ¦¬λŠ” κ²½μš°λŠ” λ‹€λ₯Έ νŽ˜μ΄μ§€λ‘œ λ„˜μ–΄κ°€κΈ° μœ„ν•¨μΌ κ²½μš°κ°€ 많기 λ•Œλ¬Έμ— λ„€λΉ„κ²Œμ΄μ…˜ λ°”λ₯Ό λ‚˜νƒ€λ‚΄λ„λ‘ μ„€κ³„ν–ˆμŠ΅λ‹ˆλ‹€.

λ”°λΌμ„œ 항상 μ΅œν•˜λ‹¨μ— λΆ™μ–΄ μžˆλ‹€κ°€
1. μŠ€ν¬λ‘€μ„ μ•„λž˜λ‘œ λ‚΄λ¦¬λŠ” 경우 숨기고
2. μœ„λ‘œ μ˜¬λ¦¬λŠ” 경우 λ‚˜νƒ€λ‚˜κ³ 
3. μŠ€ν¬λ‘€μ„ μ•„λž˜λ‘œ 내리더라도 νŽ˜μ΄μ§€μ˜ μ΅œν•˜λ‹¨μ΄λΌλ©΄ λ‚˜νƒ€λ‚˜λ„λ‘ μ„€κ³„ν–ˆμŠ΅λ‹ˆλ‹€.

πŸ“ƒ νŽ˜μ΄μ§€ ꡬ뢄

크게 5가지 νŽ˜μ΄μ§€λ‘œ κ΅¬λΆ„ν–ˆμŠ΅λ‹ˆλ‹€.
1. μΉ΄ν…Œκ³ λ¦¬
2. 검색
3. ν™ˆ
4. λ‚΄ 정보
5. μž₯λ°”κ΅¬λ‹ˆ

next.js의 useRouter().asPathλ₯Ό μ΄μš©ν•΄μ„œ ν˜„μž¬ URL에 λ§žλŠ” νŽ˜μ΄μ§€μ— λ“€μ–΄μ˜¬ 경우 ꡬ뢄할 수 μžˆλ„λ‘ λ„€μ΄κ²Œμ΄μ…˜ 바에 νŠΉμ • 색상을 μž…ν˜”μŠ΅λ‹ˆλ‹€.

μ€‘μš”ν•˜κ³  μ–΄λ €μš΄ μ½”λ“œκ°€ μ•„λ‹ˆλ―€λ‘œ μžμ„Έν•œ μ½”λ“œλŠ” μƒλž΅ν•˜κ² μŠ΅λ‹ˆλ‹€.

πŸ”’ λ„€λΉ„κ²Œμ΄μ…˜ λ°” ν•˜λ‹¨ κ³ μ •

position: fixedλ₯Ό μ΄μš©ν•΄μ„œ ν•˜λ‹¨μ— κ³ μ •μ‹œμΌ°μŠ΅λ‹ˆλ‹€.
λ‹€λ§Œ fixedλŠ” 곡쀑에 λ– μžˆλŠ” λŠλ‚ŒμœΌλ‘œ λ‹€λ₯Έ μš”μ†Œμ˜ λ ˆμ΄μ•„μ›ƒμ— 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠμœΌλ―€λ‘œ μ‹€μ œ 컨텐츠가 λ„€λΉ„κ²Œμ΄μ…˜ 바에 묻힐 수 있기 λ•Œλ¬Έμ— λ„€λΉ„κ²Œμ΄μ…˜ λ°”μ˜ λ†’μ΄λ§ŒνΌ body에 margin-bottom을 λΆ€μ—¬ν•΄μ„œ λ„€λΉ„κ²Œμ΄μ…˜ λ°”κ°€ λ“€μ–΄κ°ˆ 곡간을 λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.

μ€‘μš”ν•˜κ³  μ–΄λ €μš΄ μ½”λ“œκ°€ μ•„λ‹ˆλ―€λ‘œ μžμ„Έν•œ μ½”λ“œλŠ” μƒλž΅ν•˜κ² μŠ΅λ‹ˆλ‹€.

πŸ€” useScrollDirection ν›…

처음 λ§ν–ˆλ˜ λ„€λΉ„κ²Œμ΄μ…˜ λ°”λ₯Ό μŠ€ν¬λ‘€μ— μ˜ν•΄μ„œ μˆ¨κΈΈμ§€ 보여쀄지λ₯Ό κ²°μ •ν•˜λŠ” 데 μ‚¬μš©ν•  수 μžˆλŠ” 훅을 λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.

μžμ„Έν•œ μ„€λͺ…은 μ£Όμ„μœΌλ‘œ μž‘μ„±ν–ˆκΈ° λ•Œλ¬Έμ— μƒλž΅ν•˜κ² μŠ΅λ‹ˆλ‹€.
λ‹€λ§Œ 슀크둀 이벀트 λ“±λ‘ν•˜κΈ° λ•Œλ¬Έμ— μ“°λ‘œν‹€λ§μ„ μ μš©ν–ˆμŠ΅λ‹ˆλ‹€.

  • src/hooks/useScroll.tsx
import { useCallback, useEffect, useState } from "react";

// util
import { throttleHelper } from "@src/libs";

/**
 * λ§ˆμ§€λ§‰ 슀크둀링의 λ°©ν–₯을 μ•Œμ•„λ‚΄λŠ” ν›…
 * @returns [슀크둀 λ°©ν–₯, 슀크둀 μ΅œν•˜λ‹¨ μ—¬λΆ€, ν˜„μž¬ 슀크둀 μœ„μΉ˜] μˆœμ„œλ‘œ λ°˜ν™˜ ( boolean, boolean, number )
 */
const useScrollDirection = () => {
  // 2022/08/09 - λ§ˆμ§€λ§‰ 슀크둀 λ°©ν–₯ - by 1-blue
  const [isUp, setIsUp] = useState(false);
  // 2022/08/09 - ν˜„μž¬ 슀크둀 μœ„μΉ˜κ°’ μ €μž₯ν•  λ³€μˆ˜ - by 1-blue
  const [pageY, setPageY] = useState(0);
  // 2022/08/09 - ν˜„μž¬ 슀크둀이 μ΅œν•˜λ‹¨μ— μžˆλŠ”μ§€ νŒλ‹¨ν•  λ³€μˆ˜ - by 1-blue
  const [isBottom, setIsBottom] = useState(false);

  // 2022/08/09 - ν˜„μž¬ 슀크둀 λ°©ν–₯을 확인할 슀크둀 이벀트 ν•¨μˆ˜ - by 1-blue
  const handleScroll = useCallback(() => {
    /**
     * scrollHeight: 총 컨텐츠 높이
     * clientHeight: ν˜„μž¬ λ³΄μ΄λŠ” 높이 ( ν˜„μž¬ ν™”λ©΄(컨텐츠)의 높이 )
     * scrollY: ν˜„μž¬ 슀크둀 높이
     *
     * λ”°λΌμ„œ "총 컨텐츠 높이 === ν˜„μž¬ λ³΄μ΄λŠ” 높이 + ν˜„μž¬ 슀크둀 높이" 라면 μ΅œν•˜λ‹¨κΉŒμ§€ μŠ€ν¬λ‘€μ„ λ‚΄λ¦° 것
     */
    const {
      scrollY,
      document: {
        documentElement: { scrollHeight, clientHeight },
      },
    } = window;

    const deltaY = scrollY - pageY;
    const isUp = scrollY !== 0 && deltaY >= 0;
    const isBottom = scrollHeight - scrollY - clientHeight === 0;

    setIsUp(isUp);
    setPageY(scrollY);
    setIsBottom(isBottom);
  }, [pageY, setIsUp, setPageY, setIsBottom]);

  // 2022/08/09 - 슀크둀 μ΄λ²€νŠΈμ— μŠ€λ‘œν‹€λ§ 적용 - by 1-blue
  const throttleScroll = throttleHelper(handleScroll, 50);

  // 2022/08/09 - 슀크둀 이벀트 등둝 - by 1-blue
  useEffect(() => {
    document.addEventListener("scroll", throttleScroll);
    return () => document.removeEventListener("scroll", throttleScroll);
  }, [throttleScroll]);

  return [isUp, isBottom, pageY];
};

export default useScrollDirection;
  • src/libs/utils.ts
/**
 * μŠ€λ‘œν‹€λ§ 적용 헬퍼 ν•¨μˆ˜
 * @param callback 이후에 μ‹€ν–‰ν•  μ½œλ°±ν•¨μˆ˜
 * @param waitTime 기닀릴 μ‹œκ°„
 * @returns "waitTime"만큼 μŠ€λ‘œν‹€λ§μ΄ 적용된 ν•¨μˆ˜("callback") λ°˜ν™˜
 */
export const throttleHelper = (callback: () => void, waitTime: number) => {
  let timerId: ReturnType<typeof setTimeout> | null = null;

  return () => {
    if (timerId) return;

    timerId = setTimeout(() => {
      callback();
      timerId = null;
    }, waitTime);
  };
};

0개의 λŒ“κΈ€