ํ๋ก์ ํธ์ DnD + Carousel์ ๊ฐ์ด ์ฌ์ฉํ ๋ ๋ฌธ์ ๊ฐ ์๋์ง ํ ์คํธํ๋ ๊ณผ์ ์์ ํญ๋ชฉ์ ๋๋๊ทธํ๋ฉด์ ์์ผ๋ก ์ด๋ํ๋๊ฒ ์๋๋ ์ํฉ

์ฌ๋ฌ๊ฐ์ง ํ ์คํธ๋ฅผ ํด๋ณด๋ฉด์ ์์ธ์ ํ์ ํ์๋๋ฐ Carousel์ ์ค๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ง ์์ผ๋ฉด ์ ์์ ์ผ๋ก ๋์ํ๋ ๊ฒ์ ํ์ธํ์๋ค.
- ์ค๋ ๊ธฐ๋ฅ์ด๋?
์ฌ์ฉ์๊ฐ ์บ๋ฌ์ ์ ์ฌ๋ผ์ด๋ํ ๋, ๊ฐ ์ฌ๋ผ์ด๋๊ฐ ํ๋ฉด์ ์ ํํ ๋ง์ถฐ์ ธ ๋ณด์ด๋๋ก ํ๋ ๊ธฐ๋ฅ์ ๋งํ๋ค.
.wrap {
display: flex;
gap: 40px;
overflow-x: auto;
scroll-behavior: smooth; // ์คํฌ๋กค ๋ถ๋๋ฝ๊ฒ ์ค์
scroll-snap-type: x mandatory; // ๊ฐ๋ก ์คํฌ๋กค ๋์ ์ค๋
์ค์
scrollbar-width: none;
}
.box {
width: 780px;
min-height: 800px;
border: 1px solid #000;
display: flex;
flex-direction: column;
gap: 10px;
scroll-snap-align: start; // ์คํฌ๋กค ์ง์ ์ ๋ ฌ
}
์ค๋
๊ธฐ๋ฅ์ ์ ๊ฑฐ ํด์ฃผ๋ฉด ์ด์ ์์ผ๋ก ์ด๋์ ํ ์๋ ์์ง๋ง ๊ต์ฅํ ๋ต๋ตํ ์๋๋ก ์ด๋์ ํ๋ค.

์ด ๋ฌธ์ ๋ ์คํฌ๋กค์ ๋ถ๋๋ฝ๊ฒ ํด์ฃผ๋ ์ค์ ์ ์ ๊ฑฐ ํด์ฃผ๋ฉด ์ ์์ ์ผ๋ก ์ด๋ํ ์ ์๋ค!

์ฌ์ค ์์ ๋ฐฉ๋ฒ์ผ๋ก ์ค๋ ๊ธฐ๋ฅ, ์คํฌ๋กค ๋ถ๋๋ฝ๊ฒ ํด์ฃผ๋ ์ค์ ์ ์ ๊ฑฐํ์ฌ ์์ผ๋ก ์ด๋ํ์ง ๋ชปํ๋ ์ด์๋ ํด๊ฒฐํ์์ง๋ง ์ค๋ ๊ธฐ๋ฅ CSS ์ฝ๋๋ฅผ ์ ๊ฑฐํด์ฃผ์๊ธฐ ๋๋ฌธ์ ๋ด๊ฐ ์ง์ ์คํฌ๋กค ์ด๋ฒคํธ๋ก ์ค๋ ๊ธฐ๋ฅ์ ๊ตฌํํด์ฃผ์ด์ผ ํ๋ค...
ํ์ฌ ์ํฉ

์ฌ์ค ํ์๋ถ์ด ์ง๊ธ ๋ฐฉ์๋ ๊ด์ฐฎ๋ค๊ณ ๋ง์ํด์ฃผ์ จ์ง๋ง ์์ผ๋ก ํญ๋ชฉ์ด ๋ง๊ณ ๋ชจ๋ํฐ๊ฐ ์์ผ๋ฉด ๊ทธ๋งํผ ์ ์ ๊ฐ ๋์์์ผ์ผ ํ ์ด๋ฒคํธ๊ฐ ๋ง์์ ธ ๋ง์์ ๋ค์ง์์ ์คํฌ๋กค ์ด๋ฒคํธ๋ก ์ค๋ ๊ธฐ๋ฅ์ ๋น์ทํ๊ฒ ๊ตฌํํด๋ณด๋ ค๊ณ ํ๋ค!
๋ฐ์ค ํฌ๊ธฐ๋ฅผ ๊ณ์ฐํด์ ์ข/์ฐ ์ค์์ดํ๋ง ๊ตฌ๋ถํด์ ๊ทธ๋งํผ ์คํฌ๋กค์ ์ด๋์์ผ์ฃผ๋ฉด ์ค๋ ๊ธฐ๋ฅ๊ณผ ๊ฐ์ ๋์์ ํ ์ ์์ ๊ฒ ๊ฐ๋ค.
const handlePrevCard = () => {
cardContainer.current.scrollBy({
left: -820, // ๋ฐ์ค ํฌ๊ธฐ ๊ณ์ฐ
top: 0,
behavior: "smooth",
});
};
const handleNextCard = () => {
cardContainer.current.scrollBy({
left: 820, // ๋ฐ์ค ํฌ๊ธฐ ๊ณ์ฐ
top: 0,
behavior: "smooth",
});
};
const handleSwipeAction = (xDiff: any) => {
if (xDiff > 0) { //์ฐ์ธก ์ด๋
handleNextCard();
return;
}
// ์ข์ธก ์ด๋
handlePrevCard();
};
const handleMove = () => {
if (!xDown.current) {
return;
}
const xDiff = xDown.current - xUp.current;
if (xDiff !== 0) {
handleSwipeAction(xDiff);
}
// ์ขํ ์ด๊ธฐํ
xDown.current = null;
xUp.current = null;
};
// ๋ง์ฐ์ค ๋๋ฅผ ๋ ๋์
const handleMouseDown = (e: MouseEvent) => {
const target = e.target as HTMLElement;
if (target.dataset.status === "item") {
return;
}
xDown.current = e.clientX;
document.body.style.userSelect = "none";
};
// ๋ง์ฐ์ค ๋ ๋ ๋์
const handleMouseUp = (e: MouseEvent) => {
xUp.current = e.clientX;
handleMove();
document.body.style.userSelect = "";
};

์ด์ ๋ฐฉ์์ ๋นํด ์ค์์ดํ ํ์ ๋ ์ผ๊ด์ฑ์๋ UI๋ฅผ ๋ณผ ์ ์๋ค.
์กฐ๊ธ ๋ ์ ์ ์๊ฒ ์ข์ ํ๊ฒฝ์ ์ ๊ณตํ์ฌ UX๋ฅผ ๊ฐ์ ํ๊ณ ์ถ์ด์ ์ข/์ฐ ๋ฒํผ๋ ์ถ๊ฐํด ์ฃผ์๋ค!
