๐Ÿ–ฑ๏ธ ๋งˆ์šฐ์Šค ๋“œ๋ž˜๊ทธ๋กœ ์Šคํฌ๋กค ๊ตฌํ˜„ํ•˜๊ธฐ

Yeonnยท2025๋…„ 1์›” 31์ผ
0

๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•˜๊ธฐ

๋ชฉ๋ก ๋ณด๊ธฐ
1/10
post-thumbnail

์ฒ˜์Œ์œผ๋กœ ๋ชจ๋ฐ”์ผ ํผ์ŠคํŠธ ์›น์„ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” touch ์ด๋ฒคํŠธ๋Š” ๋˜ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•˜๋Š” ๊ฑฐ์ง€? ํ•˜๊ณ  ์—„์ฒญ ๊ฒ์„ ๋จน์—ˆ์—ˆ๋Š”๋ฐ ๋Œ€๋ถ€๋ถ„์˜ touch ์ด๋ฒคํŠธ๋„ ํด๋ฆญ๊ณผ ๋™์ผํ•˜๊ฒŒ ๊ตฌํ˜„ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค ! ๋ผ๊ณ  ํ•ด์„œ ํœด ! ํ•˜๊ณ  ์•ˆ์‹ฌํ–ˆ๋˜ ๊ธฐ์–ต์ด ์žˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ !!! ๋ชจ๋ฐ”์ผ์—์„œ๋Š” ํ„ฐ์น˜๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ขŒ์šฐ๋กœ ์Šคํฌ๋กค์ด ๋˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ ์ปดํฌ๋„ŒํŠธ ๊ฐ€ ๋ฐ์Šคํฌํƒ‘์œผ๋กœ ๋„˜์–ด์˜ค๋ฉด ์Šคํฌ๋กค ๋ฐ”๋ฅผ ์ด์šฉํ•˜์ง€ ์•Š๊ณ ๋Š” ์Šคํฌ๋กค์„ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฑธ ์•Œ๊ฒŒ๋˜์—ˆ๋‹ค. ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ด๋‹นํ•˜์‹  ๋ถ„์ด '์Šคํฌ๋กค๋ฐ”๋ฅผ ์ˆจ๊ธฐ๊ณ  ์‹ถ์—ˆ์ง€๋งŒ ์ˆจ๊ธฐ๋ฉด ์Šคํฌ๋กค์ด ์•ˆ๋ฉ๋‹ˆ๋‹ค' ๋ผ๊ณ  ํ•˜์…”์„œ ๊ทธ๊ฒŒ ๋ฌด์Šจ ์†Œ๋ฆฌ์ง€?? ํ•˜๊ณ  ๋‹น์‹œ์—๋Š” ๋‚ด ๊ตฌํ˜„๋„ ๋ฐ”๋น ์„œ ๋„˜์–ด๊ฐ”๋‹ค๊ฐ€ ํ”„๋กœ์ ํŠธ ๋งˆ๋ฌด๋ฆฌ ํ›„ ์‹œ๊ฐ„์„ ๋‚ด์–ด์„œ ๋ฆฌํŒฉํ† ๋ง์„ ํ•ด๋ณด๊ฒŒ ๋˜์—ˆ๋‹ค.

์Šคํฌ๋กค๋ฐ”๋ฅผ ์ˆจ๊ธฐ๋Š” ๊ฑด ๊ฐ„๋‹จํ–ˆ๋‹ค.

// app > globals.css 
.scrollbar-hide {
  -ms-overflow-style: none; /* IE and Edge */
  scrollbar-width: none; /* Firefox */
}

.scrollbar-hide::-webkit-scrollbar {
  display: none; /* Chrome, Safari, Opera */
}

๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์Šคํฌ๋กค ๋ฐ”๋ฅผ ์ˆจ๊ธฐ๋ ค๋Š” ์ปดํฌ๋„ŒํŠธ์— ํด๋ž˜์Šค๋ช…์œผ๋กœ scrollbar-hide๋ฅผ ๋‹ฌ์•„์ฃผ์—ˆ๋‹ค.

๊ทธ๋Ÿฌ๊ณ  ๋‚˜์„œ๋„ ์Šคํฌ๋กค์ด ์ž˜๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด์„œ ๋‹ค๋ฅธ ๋ถ€๋ถ„ ๋ฆฌํŒฉํ† ๋ง ์ž‘์—…์„ ์ž˜ ํ•˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ...
๋ฌธ๋“ ๋‚˜๋Š” ํŠธ๋ž™ ํŒจ๋“œ๋ฅผ ์“ฐ๊ณ  ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๊นจ๋‹ฌ์•˜๋‹ค....!

์ผ๋ฐ˜ ๋งˆ์šฐ์Šค๋Š” ๊ฐ€๋กœ ์Šคํฌ๋กค์„ ์–ด๋–ป๊ฒŒ ํ•˜์ง€........?
๊ทธ๋ž˜์„œ ํด๋ฆญ์œผ๋กœ ์˜ฎ๊ธฐ๋ ค๊ณ  ์•„๋ฌด๋ฆฌ ํ•ด๋ด๋„ ์•ˆ๋˜์–ด์„œ ์ด๊ฑฐ ๋•Œ๋ฌธ์— ํ•˜์‹  ๋ง์”€์ด์—ˆ๊ตฌ๋‚˜ ํ•˜๋ฉด์„œ
๋ฐฉ๋ฒ•์„ ์ฐพ๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค...!

์ผ๋‹จ ๋งˆ์šฐ์Šค ๋“œ๋ž˜๊ทธ๋กœ ์Šคํฌ๋กค ํ‚ค์›Œ๋“œ๋กœ ๊ตฌ๊ธ€๋ง์„ ์—„์ฒญ ํ•ด๋ณด๋ฉด์„œ ๋ช‡๊ฐœ์˜ ํฌ์ŠคํŒ…์„ ์ฐพ์•„๋‚ด๊ฒŒ ๋˜์—ˆ๋‹ค.

โœจEvent Listeners

  • mousedown
    • ๋งˆ์šฐ์Šค ํฌ์ธํ„ฐ๊ฐ€ ์š”์†Œ ๋ฒ”์œ„ ์•ˆ์— ์žˆ์œผ๋ฉด์„œ ๋งˆ์šฐ์Šค ์™ผ์ชฝ ๋ฒ„ํŠผ์ด ๋ˆŒ๋Ÿฌ์กŒ์„ ๋•Œ ์‹คํ–‰
    • ๋งˆ์šฐ์Šค ๋“œ๋ž˜๊ทธ ์ด๋ฒคํŠธ ์‹œ์ž‘์„ ์ด ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด ์•Œ ์ˆ˜ ์žˆ์Œ
  • mousemove
    • ๋งˆ์šฐ์Šค ์ปค์„œ์˜ ํ•ซ์ŠคํŒŸ์ด ์š”์†Œ ๋ฒ”์œ„ ์•ˆ์— ์žˆ์œผ๋ฉด์„œ ์ปค์„œ๋ฅผ ์›€์ง์˜€์„ ๋•Œ ๋ฐœ์ƒ
    • mousemove ์ด๋ฒคํŠธ์—๋‹ค ์Šคํฌ๋กค์„ ๋ฐœ์ƒ์‹œ์ผœ์ฃผ๋Š” ๋กœ์ง์„ ๋„ฃ์–ด์•ผ ํ•จ !
  • mouseup
    • ์š”์†Œ ๋ฒ”์œ„ ์•ˆ์—์„œ ๋ˆŒ๋Ÿฌ์ ธ์žˆ๋˜ ๋งˆ์šฐ์Šค ์ปค์„œ๋ฅผ ๋—์„ ๋•Œ ๋ฐœ์ƒ
    • ์ด๋•Œ ๋“œ๋ž˜๊ทธ ๋™์ž‘์„ ์ข…๋ฃŒ์‹œ์ผœ ์ฃผ๋ฉด ๋œ๋‹ค
  • mouseleave
    • ํฌ์ธํ„ฐ ์ปค์„œ๊ฐ€ ์š”์†Œ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚ฌ์„ ๋•Œ ๋ฐœ์ƒ
    • ์ด๋•Œ ์—ญ์‹œ mouseup๊ณผ ๋™์ผํ•˜๊ฒŒ ๋“œ๋ž˜๊ทธ ๋™์ž‘์ด ์ข…๋ฃŒ๋˜์–ด์•ผ ํ•  ๊ฒƒ !


๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  const scrollRef = useRef<HTMLDivElement>(null); // DOM์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ ref ๊ฐ’
  const [isDragging, setIsDragging] = useState(false); // ๋“œ๋ž˜๊ทธ ์ค‘์ธ๊ฐ€ ?
  const [startX, setStartX] = useState(0); // ๋“œ๋ž˜๊ทธ ์‹œ์ž‘ ์ง€์ 
  const [scrollLeft, setScrollLeft] = useState(0); // ํ˜„์žฌ ์Šคํฌ๋กค ์œ„์น˜: ์ž๋™ ์—…๋ฐ์ดํŠธ

  const handleMouseDown = (e: React.MouseEvent) => {
    if (!scrollRef.current) return;
    
    setIsDragging(true); // ๋“œ๋ž˜๊ทธ( ์Šคํฌ๋กค ) ์‹œ์ž‘
    setStartX(e.pageX - scrollRef.current.offsetLeft); // ํด๋ฆญ ์œ„์น˜๋ฅผ ๊ธฐ์ค€์  ์ง€์ •
    setScrollLeft(scrollRef.current.scrollLeft); // ์‹œ์ž‘์ „ scrollLeft ๊ฐ’ ์ง€์ •
  };

  const handleMouseMove = (e: React.MouseEvent) => {
    if (!isDragging || !scrollRef.current) return; // ๊ณผํ•œ ๊ณ„์‚ฐ ๋ฐฉ์ง€ !
    e.preventDefault(); 
    e.stopPropagation();
    const x = e.pageX - scrollRef.current.offsetLeft; // ํ˜„์žฌ ๋งˆ์šฐ์Šค X ์œ„์น˜ ๊ณ„์‚ฐ
    const walk = (x - startX) * 2; // ์ด๋™ ๊ฑฐ๋ฆฌ( ๋ถ€๋“œ๋Ÿฌ์šด ์ด๋™ )
    scrollRef.current.scrollLeft = scrollLeft - walk; // ์Šคํฌ๋กค ๊ฑฐ๋ฆฌ๋งŒํผ ์Šคํฌ๋กค ์ด๋™
  };

  const handleMouseUp = () => {
    setIsDragging(false); // ๋“œ๋ž˜๊ทธ ์ค‘๋‹จ !
  };

// ...codes

<div ref={scrollRef}
	onMouseDown={handleMouseDown}
	onMouseMove={handleMouseMove}
	onMouseUp={handleMouseUp}
	onMouseLeave={handleMouseUp}
	className={`scrollbar-hide scroll-smooth  ${isDragging ? 'cursor-grabbing' : 'cursor-grab'}`}`}

๐Ÿ‘ฉโ€๐Ÿ’ป ์ตœ์ข… ์ •๋ฆฌ

  • scrollLeft๋Š” div์˜ ํ˜„์žฌ ์ˆ˜ํ‰ ์Šคํฌ๋กค ์œ„์น˜(px)
  • ์œ ์ €๊ฐ€ ๋งˆ์šฐ์Šค๋กœ ํด๋ฆญ( mousedown )ํ•˜๋ฉด scrollLeft๋ฅผ ์ €์žฅ
  • ๋งˆ์šฐ์Šค๋ฅผ ์ด๋™( mousemove )ํ•  ๋•Œ ๊ธฐ์กด scrollLeft ๊ฐ’์—์„œ ์ƒˆ๋กœ์šด ์œ„์น˜๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ ์Šคํฌ๋กค ์ด๋™
  • ๋งˆ์šฐ์Šค๋ฅผ ๋–ผ๋ฉด( mouseup ) ํ˜น์€ ๋งˆ์šฐ์Šค๊ฐ€ ๋– ๋‚˜๋ฉด( mouseleave ), isDragging์„ false๋กœ ์„ค์ •ํ•˜์—ฌ ๋“œ๋ž˜๊ทธ ์ข…๋ฃŒ.

๐Ÿš€ ์ฐธ๊ณ ํ•œ ๋งํฌ

0๊ฐœ์˜ ๋Œ“๊ธ€