[React] ๋ฆฌ์กํธ ์์ ๋๋๊ทธ์ค๋๋กญ ๊ตฌํ

TL;DR
- ๋๋๊ทธํ ์ ์๋ ์์๋ก ๋ณ๊ฒฝ โ
draggable={true}
- ๋๋๊ทธ ์์ โ onDragStart ์ด๋ฒคํธ ํธ๋ฆฌ๊ฑฐ
- ๋๋๊ทธํ๊ณ ์๋ ์์์ ์ธ๋ฑ์ค ์ ๋ณด ์ ์ฅ โ
state.draggedFrom
- ๋๋๊ทธ ์ํ true๋ก ๋ณ๊ฒฝ โ
state.isDragging
- ์ด๋ฒคํธ ํธ๋ฆฌ๊ฑฐ ์์ ์ ์๋ฆฌ๋จผํธ ๋ฆฌ์คํธ ์ ์ฅ โ
state.originalOrder
- ๋๋๊ทธํ๊ณ ์๋ ์์์ ์ธ๋ฑ์ค ์ ๋ณด ์ ์ฅ โ
- ๋ง์ฐ์ค ์ปค์๊ฐ ๋๋กญ ๊ฐ๋ฅํ ์์ญ์ ์์ ๋ โ onDragOver ์ด๋ฒคํธ ํธ๋ฆฌ๊ฑฐ
- drop ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก dragOver ๊ธฐ๋ณธ ์ด๋ฒคํธ ๋ฐฉ์ง โ
e.preventDefault()
- ๋ง์ฐ์ค ํฌ์ธํฐ ์์น์ ์๋ ์์์ ์ธ๋ฑ์ค ์ ์ฅ โ
state.draggedTo
- ์๋ฆฌ๋จผํธ ์์ ๋ณ๊ฒฝ โ
state.updatedOrder
๋๋๊ทธ์ค์ธ ์์ดํ ์ ๋ง์ฐ์ค ํฌ์ธํฐ ์์น(draggedTo ์ธ๋ฑ์ค)๋ก ์ด๋. ๊ธฐ์กด ๋ง์ฐ์ค ํฌ์ธํฐ ์์น์ ์๋ ์์๋ ๋ฐ๋ก ๋ค๋ก ๋ฐ๋ฆผ.
- drop ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก dragOver ๊ธฐ๋ณธ ์ด๋ฒคํธ ๋ฐฉ์ง โ
- ๋๋กญ ๊ฐ๋ฅํ ์์ญ์์ ๋๋กญํ์ ๋ โ onDrop ์ด๋ฒคํธ ํธ๋ฆฌ๊ฑฐ
- ์์๋ฅผ ๋ณ๊ฒฝํ ์๋ฆฌ๋จผํธ ๋ฆฌ์คํธ ๋ ๋
- ๋๋๊ทธ์ค๋๋กญ ๊ด๋ จ ์ํ ์ด๊ธฐํ
๋ฐฐ๊ฒฝ ์ง์
HTML ๋๋๊ทธ์ค๋๋กญ Web API๋ฅผ ์ด์ฉํด ๋ฆฌ์คํธ ์๋ฆฌ๋จผํธ์ ์์๋ฅผ ๋ง์ฐ์ค ๋๋๊ทธ์ค๋๋กญ์ผ๋ก ๋ฐ๊ฟ ์ ์๋ค. ์๋ฆฌ๋จผํธ์ draggable
์์ฑ์ true
๋ก ์ฃผ๋ฉด ํด๋น ์์๋ ๋๋๊ทธ ๊ฐ๋ฅํ ๊ฐ์ฒด๊ฐ ๋๋ค. ์ด๋ฏธ์ง, ๋งํฌ, ์ ํํ ํ
์คํธ(ํ
์คํธ ๋ธ๋ก)๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋๋๊ทธํ ์ ์๋ค. ๋๋๊ทธ ๊ฐ๋ฅ ์ํ๊ฐ ๋๋ฉด onDragStart
๊ฐ์ ๋๋๊ทธ ๊ด๋ จ ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํ ์ ์๋ค. onDragStart
๋ ๋๋๊ทธ๊ฐ ์์๋๋ฉด ํธ๋ฆฌ๊ฑฐ๋๋ ์ด๋ฒคํธ๋ค.
// ๋ฆฌ์คํธ ์์ <div draggable="true" onDragStart={startDragging}> Drag Me ๐ฐ </div>;
์๋ฆฌ๋จผํธ์ onDrop
๊ณผ onDragOver
์ด๋ฒคํธ๋ฅผ ๊ฑธ๋ฉด ๋๋กญ ๊ฐ๋ฅํ ์์ญ(์ ํจํ ๋๋กญ ๋์)์ด ๋๋ค. ์ด ๋ ์ด๋ฒคํธ๋ฅผ ํ์ฉํด ๋๋๊ทธ์ค๋๋กญ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์๋ค. onDragOver
๋ ๋ง์ฐ์ค ํฌ์ธํฐ์ ์๋ ์์๊ฐ ์ ํจํ ๋๋กญ ๋์์ผ ๋ ํธ๋ฆฌ๊ฑฐ ๋๋ฉฐ, onDrop
์ ๋๋กญ ๊ฐ๋ฅํ ์์ญ์์ ๋๋กญํ์ ๋ ํธ๋ฆฌ๊ฑฐ๋๋ ์ด๋ฒคํธ๋ค.
<section onDrop={updateDragAndDropState} onDragOver={receiveDraggedElements}> Drop here ๐คฒ๐ป </section>;
๋๋๊ทธํ (์์)๋ฐ์ดํฐ์ ์ํธ ์์ฉํ๊ธฐ ์ํด setData()
์ getData()
๊ฐ์ ์ด๋ฒคํธ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์๋ ์๋ค. ํ์ฌ ๋๋๊ทธ ํ๊ณ ์๋ ์์ ์ ๋ณด(id ๋ฑ)๋ฅผ setData()
๋ฅผ ํตํด ์ ์ฅํ๊ณ , ๋๋กญํ์ ๋ getData()
๋ฅผ ํตํด ์์ ์ ๋ณด๋ฅผ ๋ถ๋ฌ์จ ํ ์ฌ์ ๋ ฌ ํ๋ ๋ฐฉ์์ผ๋ก ํ์ฉํ ์ ์๋ค.
event.dataTransfer.setData(key, value); // ์ฌ๋ฌ key๋ฅผ ์ด์ฉํด ๋ค์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ ์๋ค event.dataTransfer.getData(key);
์ํ
๋ฆฌ์กํธ ์ปดํฌ๋ํธ ๋ฐ๊นฅ ์์ญ์ ๋ฆฌ์คํธ๋ฅผ ๋ ๋ํ ์ํ(items)์, ๋๋๊ทธ์ค๋๋กญ๊ณผ ๊ด๋ จํ ์ํ์ ์ด๊ธฐ๊ฐ์ ์ ์ํ๋ค. ๋๋๊ทธ์ค๋๋กญ ์ํ์ ๋๋๊ทธ ์ค์ธ ์์์ ์ธ๋ฑ์ค, ์ ๋ฐ์ดํธ ์ ํ์ ๋ ๋ ๋ฆฌ์คํธ(items), ๋๋๊ทธ ์ํ๋ฅผ ์ ์ฅํ๋ ๊ณณ์ด๋ค.
const items = [ { number: "3", title: "๐จ๐ปโ๐ป Tech Man" }, // ์๋ต ]; const initialDnDState = { draggedFrom: null, // ๋๋๊ทธ๋ฅผ ์์ํ ์์์(๋ง์ฐ์ค๋ฅผ ํด๋ฆญํ์ฌ ์์ง์ธ ์์) ์ธ๋ฑ์ค draggedTo: null, // ๋๋กญ ๋์ ์์์ ์ธ๋ฑ์ค(๋๋๊ทธํ์ฌ ๋ง์ฐ์ค ์ปค์๊ฐ ์์นํ ์์์ ์ธ๋ฑ์ค) isDragging: false, // ๋๋๊ทธ ์ฌ๋ถ Boolean originalOrder: [], // ๋๋กญํ๊ธฐ์ (์์๊ฐ ๋ฐ๋๊ธฐ ์ ) ๊ธฐ์กด list updatedOrder: [], // ๋๋กญํ ํ ์์๊ฐ ๋ฐ๋ list };
useState
ํ
์ ์ด์ฉํด ๋ ๋ ๋ฆฌ์คํธ์ ๋๋๊ทธ์ค๋๋กญ ์ด๊ธฐ๊ฐ์ ์ปดํฌ๋ํธ ๋ด๋ถ ์ํ๋ก ๋๋ค.
const Lists = () => { const [list, setList] = useState(items); // ๋ ๋๋ ์์ const [dragAndDrop, setDragAndDrop] = useState(initialDnDState); // D&D ๊ด๋ จ ์ํ return ( <section> <ul> {list.map((item, index) => ( <li>...</li> ))} </ul> </section> ); };
๋๋๊ทธ ๊ฐ๋ฅํ ์์๋ก ๋ณ๊ฒฝ
โ๋งํฌ โ์ด๋ฏธ์ง โ์ ํํ ํ ์คํธ(ํ ์คํธ ๋ธ๋ก)๋ ๊ธฐ๋ณธ๊ฐ์ด ๋๋๊ทธ ๊ฐ๋ฅ์ด๋ค(draggable="ture")
<li>
ํ๊ทธ์ draggable
์์ฑ์ true
๋ก ๋ณ๊ฒฝํ์ฌ ๋๋๊ทธ ๊ฐ๋ฅํ ์์๊ฐ ๋๋๋ก ํ๋ค. ํ์ฌ ๋๋๊ทธ ํ๊ณ ์๋ ์์๋ฅผ ํ๋ณํ๊ณ ์ฌ์ ๋ ฌํ ๋ ์ฌ์ฉํ๊ธฐ ์ํด ์์์ index
๋ฅผ data ์์ฑ์ ํ ๋นํ๋ค.
data ์์ฑ์ data-๋ฐ์ดํฐ์ด๋ฆ
ํ์์ผ๋ก ์ ์ํ๊ณ , elem.dataset.๋ฐ์ดํฐ์ด๋ฆ
์ผ๋ก ์กฐํํ ์ ์๋ค.
return ( <section> <ul> {list.map((item, index) => ( <li draggable={true} data-position={index}> <span>{item.number}</span> <p>{item.title}</p> </li> ))} </ul> </section> );
๋๋๊ทธ ์ด๋ฒคํธ ํธ๋ค๋ฌ
onDragOver์ onDrop ์ด๋ฒคํธ๊ฐ ๊ฑธ๋ ค์๋ DOM์ด ๋๋กญ ๊ฐ๋ฅํ ์์ญ(์ ํจํ ๋๋กญ ๋์)์ด ๋๋ค.
onDragStart
, onDragOver
, onDrop
๋ฐ onDragLeave
(์ ํ) 3๊ฐ์ ์ด๋ฒคํธ๊ฐ ํ์ํ๋ค.
- onDragStart : ๋๋๊ทธ๋ฅผ ์์ํ ๋(๋ง์ฐ์ค๋ฅผ ํด๋ฆญํ ํ ์์ง์ผ ๋) ํธ๋ฆฌ๊ฑฐ
- onDragOver : ๋ง์ฐ์ค ์๋์ ์๋ ์์๊ฐ ์ ํจํ ๋๋กญ ๋์์ผ ๋(์์ดํ
์ด ๋๋กญ๋ ์ ์๋ ๊ณณ) ํธ๋ฆฌ๊ฑฐ
โ ๋ง์ฐ์ค๊ฐ ์ ํจํ ๋๋กญ ๋์ ์์ ์์นํด ์๋ค๋ฉดonDragOver
์ด๋ฒคํธ๊ฐ ์๋ฐฑ ๋ฐ๋ฆฌ ์ด๋ง๋ค ๊ณ์ ํธ๋ฆฌ๊ฑฐ ๋จ - onDrop : ๋๋กญ ๊ฐ๋ฅํ ์์ญ์์ ๋ง์ฐ์ค ํด๋ฆญ์ ํด์ ํ์ฌ ๋๋กญํ์ ๋ ํธ๋ฆฌ๊ฑฐ
- onDragLeave : ๋๋กญ ๊ฐ๋ฅํ ์์ญ์ ๋ฒ์ด๋ฌ์ ๋ ํธ๋ฆฌ๊ฑฐ
- onDragEnter : ๋๋กญ ๊ฐ๋ฅํ ์์ญ์ผ๋ก(๋์ ๊ฐ์ฒด) ์ฒ์ ์ง์ ํ์ ๋ ํธ๋ฆฌ๊ฑฐ
onDragStart โ ๋๋๊ทธ ์์
๋๋๊ทธํ๋ ๋์ draggable ์์๋ ๋ฐํฌ๋ช ํํ๋ก ๋ง์ฐ์ค ํฌ์ธํฐ๋ฅผ ๋ฐ๋ผ๋ค๋๋ค
๋ง์ฐ์ค๋ก ์์๋ฅผ ํด๋ฆญํ๊ณ ๋๋๊ทธ๋ฅผ ์์ํ๋ฉด onDragStart
์ด๋ฒคํธ๊ฐ ํธ๋ฆฌ๊ฑฐ ๋๋ค. ์ด ์ด๋ฒคํธ ํธ๋ค๋ฌ์์ โ๋๋๊ทธํ๊ณ ์๋ ์์์ ์ธ๋ฑ์ค ์ ๋ณด๋ฅผ ์กฐํํ ํ ์ ์ฅํ๊ณ , โ๋๋๊ทธ ์ํ๋ฅผ true
๋ก ๋ณ๊ฒฝํ๊ณ , โํด๋น ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ์์ ์ ์๋ฆฌ๋จผํธ ๋ฆฌ์คํธ ์ํ๋ฅผ ์ ์ฅํ๋ค.
const onDragStart = (e) => { const initialPosition = Number(e.target.dataset.position); setDragAndDrop({ ...dragAndDrop, draggedFrom: initialPosition, // ๋๋๊ทธ๋ฅผ ์์ํ ์์์ ์ธ๋ฑ์ค isDragging: true, originalOrder: list, // ํ์ฌ list ์ํ ์ ์ฅ }); };
onDragOver โ ๋๋กญ ๊ฐ๋ฅ ์์ญ โก๏ธ
onDragOver ์ด๋ฒคํธ๋ ์๋ฐฑ ๋ฐ๋ฆฌ์ด๋ง๋ค ๋ฐ๋ํ๊ณ ์ด์ ๋น์ทํ onDragEnter๋ ๋จ ํ๋ฒ๋ง ๋ฐ๋ํ๋ค.
๋๋๊ทธ ์ํ์์ ๋ง์ฐ์ค ํฌ์ธํฐ์ ์๋ ์์๊ฐ ์ ํจํ ๋๋กญ ๋์์ผ ๋ onDragOver
์ด๋ฒคํธ๊ฐ ํธ๋ฆฌ๊ฑฐ๋๋ค. ์ด๋ ์ด๋ฒคํธ target(event.target)์ ๋ง์ฐ์ค ์ปค์ ์๋์ ์์๋ฅผ ๊ฐ๋ฆฌํจ๋ค. ์ด ํธ๋ค๋ฌ์์ ์์๋ฅผ ๋๋กญํ์ ๋ ๋ ๋ํ ๋ฆฌ์คํธ๋ฅผ ๋ฏธ๋ฆฌ ์ค๋นํด๋๋ ์์
(๋ง์ฐ์ค ํฌ์ธํฐ์ ๋ฐ๋ผ ์์ ์์ ๋ณ๊ฒฝ)์ ์ํํ๋ค.
โถ onDragOver
, onDragEnter
์ด๋ฒคํธ๋ ๋๋กญ ์ด๋ฒคํธ๋ฅผ ์ทจ์์ํค๋ ๊ธฐ๋ณธ ์ด๋ฒคํธ๋ฅผ ๊ฐ์ง๋ค. ๋๋กญ ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด(๋๋กญ ํ์ฉ) e.preventDefault()
๋ฉ์๋๋ก ๊ธฐ๋ณธ ๋์์ ๋ฐฉ์งํ๋ค โ ์ฐธ๊ณ ๋งํฌ
โท ํ์ฌ ๋ง์ฐ์ค๊ฐ hover๋๊ณ ์๋(๊ฐ๋ฆฌํค๊ณ ์๋) ์์ญ์ item ์ธ๋ฑ์ค ์ ์ฅ โ draggedTo
โธ ํ์ฌ ๋๋๊ทธํ๊ณ ์๋ ์์๋ฅผ ์ ์ธํ item ๋ฆฌ์คํธ ์ ์ฅ โ remainingItems
โน ๋ฆฌ์คํธ ์์ ๋ณ๊ฒฝ. ํ์ฌ ๋๋๊ทธ์ค์ธ ์์ดํ
์ draggedTo
์ธ๋ฑ์ค๋ก(์์น)๋ก ์ถ๊ฐ โ updatedOrder
๋๋๊ทธํ๊ณ ์๋ ์์๊ฐ 4
(3๋ฒ ์ธ๋ฑ์ค), ํธ๋ฒ์ค์ธ ์์๊ฐ 2
(1๋ฒ ์ธ๋ฑ์ค)๋ผ๊ณ ๊ฐ์ . ์์ 4
๊ฐ ์์ 2
์ ์์น๋ก ์ด๋ํ๊ณ , ์์ 2
๋ ์์ 4
๋ค๋ก ๊ฐ๊ฒ๋ ๋ณ๊ฒฝํ๋ค
const list = [1, 2, 3, 4, 5]; // ์ํ๋ ๊ฒฐ๊ณผ๊ฐ [1, 4, 2, 3, 5] const filtered = list.filter((el) => el !== 4); // [1, 2, 3, 5] ๋๋๊ทธํ๊ณ ์๋ ์์ ์ ์ธ const from = filtered.slice(0, 1); // [1] const to = filtered.slice(1); // [2, 3, 5] const result = [...from, 4, ...to]; // [1, 4, 2, 3, 5]
โบ dragAndDrop ์ํ์ updatedOrder
๋ฐ draggedTo
์
๋ฐ์ดํธ. ๋ง์ฝ dragAndDrop
์ํ์ ์ ์ฅํ draggedTo
์ ํ์ฌ ์ด๋ฒคํธ๊ฐ ํธ๋ฆฌ๊ฑฐ๋ผ์ ์ ์ฅํ draggedTo
๊ฐ์ด ๊ฐ๋ค๋ฉด ๋๋๊ทธ์ค๋๋กญ ์ํ ์
๋ฐ์ดํธ๋ ์คํตํ๋ค.
const onDragOver = (e) => { e.preventDefault(); // onDragOver ๊ธฐ๋ณธ ์ด๋ฒคํธ ๋ฐฉ์ง const draggedTo = Number(e.target.dataset.position); // ํ์ฌ hover ๋๊ณ ์๋(๋ง์ฐ์ค๊ฐ ์์นํ) item์ ์ธ๋ฑ์ค const { originalOrder, draggedFrom } = dragAndDrop; // ๊ธฐ์กด ๋ฆฌ์คํธ ๋ฐ ๋๋๊ทธ์ค์ธ ์์์ ์ธ๋ฑ์ค ์กฐํ const remainingItems = originalOrder.filter( (_, index) => index !== draggedFrom, // ํ์ฌ ๋๋๊ทธ ํ๊ณ ์๋ ์์๋ฅผ ์ ์ธํ items ๋ชฉ๋ก ); // ๋ฆฌ์คํธ ์์ ๋ณ๊ฒฝ. // ํ์ฌ ๋๋๊ทธ์ค์ธ ์์ดํ
์ draggedTo(ํ์ฌ ๋ง์ฐ์ค๊ฐ ์์นํ) ์ธ๋ฑ์ค ์์น๋ก ์ถ๊ฐ const updatedOrder = [ ...remainingItems.slice(0, draggedTo), originalOrder[draggedFrom], // ํ์ฌ ๋๋๊ทธ์ค์ธ ์์ดํ
...remainingItems.slice(draggedTo), ]; // ์์ ๋ณ๊ฒฝํ ๋ฆฌ์คํธ ๋ฐ hover ์์์ ์ธ๋ฑ์ค(draggedTo) ์
๋ฐ์ดํธ. // ์ํ์ ์ ์ฅํ hover ์์ ์ธ๋ฑ์ค์ ๊ฐ์ง ์์๋๋ง ์
๋ฐ์ดํธํ๋ค if (draggedTo !== dragAndDrop.draggedTo) { setDragAndDrop({ ...dragAndDrop, updatedOrder, // ๋๋กญ ์ด๋ฒคํธ๊ฐ ํธ๋ฆฌ๊ฑฐ๋๋ฉด ํด๋น ๋ฆฌ์คํธ๊ฐ ๋ ๋๋จ draggedTo, }); } };
onDrop โ ๋๋กญ
๋๋กญ ๊ฐ๋ฅํ ์์ญ์์ ๋๋กญํ์ ๋ onDrop
์ด๋ฒคํธ๊ฐ ํธ๋ฆฌ๊ฑฐ๋๋ค. onDropOver
์์ ์์
ํ๋, ์์๋ฅผ ๋ณ๊ฒฝํ ๋ฆฌ์คํธ๋ฅผ ๋ ๋๋ ๋ฆฌ์คํธ(list)๋ก ์
๋ฐ์ดํธํ๊ณ dragAndDrop
์ํ๋ฅผ ์ด๊ธฐํํ๋ค.
const onDrop = () => { // onDropOver์์ ์์
ํด๋(๋ง์ฐ์ค ์ปค์์ ๋ฐ๋ผ ์์๋ฅผ ๋ณ๊ฒฝํ) ์์ ๋ฆฌ์คํธ ์
๋ฐ์ดํธ setList(dragAndDrop.updatedOrder); // dragAndDrop ์ํ ์ด๊ธฐํ setDragAndDrop({ ...dragAndDrop, draggedFrom: null, draggedTo: null, isDragging: false, }); };
onDragLeave
๋๋กญ ๊ฐ๋ฅํ ์์ญ์ ๋ฒ์ด๋ฌ์ ๋ onDragLeave
์ด๋ฒคํธ๊ฐ ํธ๋ฆฌ๊ฑฐ๋๋ค. ๋๋กญ ๋์ ์์์ ๋ํ ์ธ๋ฑ์ค๋ฅผ ๋ด๋ ์ํ์ธ DraggedTo
์ํ ๊ฐ์ null
๋ก ์ค์ ํ๋ค โ ๋๋กญ ๊ฐ๋ฅํ ์์ญ์ ๋ฒ์ด๋์ ๋๋กญ ๊ฐ๋ฅํ ์์ ์์ฒด๊ฐ ์์ผ๋ฏ๋ก
const onDragLeave = () => { setDragAndDrop({ ...dragAndDrop, draggedTo: null, }); };
ํธ๋ค๋ฌ ํ ๋น
์์์ ์์ฑํ ํธ๋ค๋ฌ๋ฅผ Drop ์์ญ์ด ๋ ๊ณณ์ธ <li>
ํ๊ทธ์ ํ ๋นํ๋ค. onDragOver
์ onDrop
์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ํ ๋นํ๋ฉด, ํด๋น ์์๋ ๋๋กญ ๊ฐ๋ฅํ ์์ญ์ด ๋๋ค.
return ( <section> <ul> {list.map((item, index) => ( <li // ... onDragStart={onDragStart} onDragLeave={onDragLeave} onDragOver={onDragOver} onDrop={onDrop} ></li> // ... ))} </ul> </section> );
CSS
Placeholder ์คํ์ผ

๋๋กญํ ์์น์ ์ ์ ๋ชจ์์ Placeholder ์คํ์ผ์ ์ ์ฉํด ์๊ฐ์ ํํธ๋ฅผ ์ค ์ ์๋ค. draggedTo
์ํ(๋๋๊ทธ๋ฅผ ์์ํ ํ ๋ง์ฐ์ค ์ปค์๊ฐ ์์นํ ์์์ ์ธ๋ฑ์ค)์ ๋ ๋ํ ์์์ ์ธ๋ฑ์ค๊ฐ ๊ฐ๋ค๋ฉด .dropArea
ํด๋์ค๋ฅผ ์ถ๊ฐํ๊ณ , ํด๋น ํด๋์ค์ ๋ํ placeholder ์คํ์ผ์ ์ง์ ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๊ตฌํํ ์ ์๋ค.
return ( <section> <ul> {list.map((item, index) => ( <li className={dragAndDrop?.draggedTo === Number(index) ? "dropArea" : ""} // ... ></li> // ... ))} </ul> </section> );
์คํ์ผ์ ์ํ ๋ชฉ์ ์ด๋ฏ๋ก ๋ฐ๋ก ํ๊ทธ๋ฅผ ์ถ๊ฐํ์ง ์๊ณ ::before
์๋ ์๋ฆฌ๋จผํธ๋ฅผ ์ด์ฉํ๋ค. ๋๋๊ทธ๋ฅผ ์์ํ์ฌ ๋ง์ฐ์ค ์ปค์๊ฐ ์์นํ ์์์ <li>
์คํ์ผ์ .dropArea
ํด๋์ค ์คํ์ผ์ด ์ ์ฉ๋๋ค.
li { // ... &.dropArea { color: white !important; // ์ด๋ชจํฐ์ฝ์ ์ ์ธํ ํ
์คํธ ๋ชจ๋ ํฐ์์ผ๋ก background: white !important; position: relative; &::before { content: "Drop Here"; color: "#687bf7"; font-size: 0.5em; text-transform: uppercase; // ๋๋ฌธ์ width: 100%; height: 100%; border: 2px dashed "#687bf7"; // ์ ์ border-radius: 3px; position: absolute; display: flex; justify-content: center; align-items: center; } span { display: none; // ์์ดํ
๋๋ฒ ๊ฐ์ถ๊ธฐ } p { margin-left: 1em; } } // ... }
Margin ์ฌ๋ฐฑ ์ ๋๋ฉ์ด์
transition
์์ฑ์ ํ์ฉํด ๋ง์ฐ์ค๋ฅผ ๋๋๊ทธํ์ฌ Placeholder ์คํ์ผ์ด ์ ์ฉ๋๊ณ , ๋ค์ ๊ธฐ์กด <li>
์คํ์ผ๋ก ๋์์ฌ ๋๋ง๋ค ์์์ ํ
์คํธ๊ฐ ์์ง์ด๋ ๋ฏํ ํจ๊ณผ๋ฅผ ์ค ์๋ ์๋ค.
li { p { // margin-left๊ฐ ์ ์ฉ๋๊ธฐ๊น์ง์ ์๊ฐ์ 50ms๋ก ์ค์ transition: margin-left 50ms ease-in-out; } }
๋ ํผ๋ฐ์ค
๊ธ ์์ ์ฌํญ์ ๋ ธ์ ํ์ด์ง์ ๊ฐ์ฅ ๋น ๋ฅด๊ฒ ๋ฐ์๋ฉ๋๋ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์
'๐ช Programming' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋ค๋ฅธ ๊ธ
-
[JS] ์๋ฐ์คํฌ๋ฆฝํธ ๋๋ฐ์ด์ค Debounce, ์ค๋กํ Throttle ๊ตฌํํ๊ธฐ
[JS] ์๋ฐ์คํฌ๋ฆฝํธ ๋๋ฐ์ด์ค Debounce, ์ค๋กํ Throttle ๊ตฌํํ๊ธฐ
2024.04.29 -
[Git] Github ๋งํฌ๋ค์ด์ ๊ฐ์ฃผ ๋ฌ๊ธฐ
[Git] Github ๋งํฌ๋ค์ด์ ๊ฐ์ฃผ ๋ฌ๊ธฐ
2024.04.29 -
[Algorithm] ํน์ ์ ๊น์ง์ ํฉ ๊ตฌํ๊ธฐ / ๋ฑ์ฐจ์์ด (๊ฐ์ฐ์ค ๊ณต์)
[Algorithm] ํน์ ์ ๊น์ง์ ํฉ ๊ตฌํ๊ธฐ / ๋ฑ์ฐจ์์ด (๊ฐ์ฐ์ค ๊ณต์)
2024.04.28 -
[CS] ์ง๋ฒ ๊ณ์ฐ ๋ฐฉ๋ฒ โ 10์ง์ โ 2์ง์ ๋ณํ
[CS] ์ง๋ฒ ๊ณ์ฐ ๋ฐฉ๋ฒ โ 10์ง์ โ 2์ง์ ๋ณํ
2024.04.28
๋๊ธ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.