λ°λλΌ μλ°μ€ν¬λ¦½νΈλ‘ λλκ·Έ μ€ λλ‘ UI μ»΄ν¬λνΈ κ΅¬ννκΈ° – μ€μ μ¬λ‘ μ€μ¬
μΉ UIμμ μ¬μ©μμμ μνΈμμ©μ μμ°μ€λ½κ² λ§λλ λ°©λ² μ€ νλκ°
λ°λ‘ λλκ·Έ μ€ λλ‘ μΈν°νμ΄μ€(Drag and Drop UI) μ λλ€.
νμΌ μ²¨λΆ, 리μ€νΈ μ λ ¬, λμ보λ κ΅¬μ± λ± λ€μν μ€λ¬΄ μ¬λ‘μμ μ¬μ©λλ μ΄ κΈ°λ₯μ
μ¬μ©μ κ²½ν(UX)μ ν¬κ² ν₯μμν¬ μ μμ΅λλ€.
μ΄ κΈμμλ λ°λλΌ μλ°μ€ν¬λ¦½νΈ(Vanilla JavaScript)λ₯Ό νμ©νμ¬
λ€μ μΈ κ°μ§ μ€μ μ¬λ‘λ₯Ό μ€μ¬μΌλ‘ λλκ·Έ μ€ λλ‘ UIλ₯Ό ꡬνν΄ λ³΄κ² μ΅λλ€.
- β Gmail μ€νμΌμ νμΌ μ²¨λΆ λλ‘μ‘΄
- β TODO μ±μμ ν μΌ μμ λ³κ²½ κΈ°λ₯
- β λμ보λ μμ ― μμΉ μ΄λ UI
π 1. νμΌ μ²¨λΆ λλ‘μ‘΄ UI – Gmail μ€νμΌ κ΅¬ν
λλκ·Έ μ€ λλ‘ λ°©μμΌλ‘ νμΌμ 첨λΆν μ μλ UIλ
μ΄λ©μΌ, κ²μν, κ΄λ¦¬μ νμ΄μ§ λ±μμ λ§μ΄ μ¬μ©λ©λλ€.
π§ μ£Όμ κΈ°λ₯
- dragenter, dragover, drop μ΄λ²€νΈλ₯Ό νμ©ν λλ‘μ‘΄ ꡬν
- μ λ‘λλ νμΌ λͺ©λ‘ μ€μκ° μκ°ν
- νμΌ νμ νν°λ§ λ° μ΄λ―Έμ§ 미리보기
π‘ UX κ°ν ν
- μ¬μ©μκ° νμΌμ λλ‘ν λ λ°°κ²½μ λ³κ²½ λ± μκ°μ νΌλλ°± μ 곡
- DataTransfer.itemsλ₯Ό νμ©ν΄ ν΄λ λλκ·Έ λ°©μ§ μ²λ¦¬
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
const files = [...e.dataTransfer.files];
renderFileList(files);
});
π 2. 리μ€νΈ μ λ ¬ κΈ°λ₯ – TODO 리μ€νΈ νλͺ© μμ λ³κ²½
λλκ·Έλ₯Ό ν΅ν΄ ν μΌ λͺ©λ‘μ μμλ₯Ό λ³κ²½ν μ μλ€λ©΄
μ¬μ©μλ λμ± μ§κ΄μ μΌλ‘ 리μ€νΈλ₯Ό μ‘°μν μ μμ΅λλ€.
π§ μ£Όμ κΈ°λ₯
- κ° νλͺ©μ draggable="true" μμ± λΆμ¬
- dragstart, dragover, drop μ΄λ²€νΈλ‘ DOM μμ μΆμ λ° μ λ ¬
- insertBefore λ©μλλ₯Ό νμ©ν΄ 리μ€νΈ μμ λ³κ²½
π‘ UX κ°ν ν
- λλκ·Έ μ€μΈ νλͺ©μ dragging ν΄λμ€ μΆκ°νμ¬ μ€νμΌ κ°ν
- λλ‘ μμΉμ μκ°μ ννΈ(placeholder DOM) μΆκ°
list.addEventListener('drop', (e) => {
const dragged = document.querySelector('.dragging');
const target = e.target.closest('li');
list.insertBefore(dragged, target);
});
π¦ 3. λμ보λ μμ ― μ΄λ – λ°μ€ κΈ°λ° λλκ·Έ ꡬν
HTML Drag API μΈμλ mousedown, mousemove, mouseupλ₯Ό νμ©ν
컀μ€ν λ°©μμ λλκ·Έ UIλ κ°λ₯ν©λλ€.
νΉν λμ보λμ μΉ΄λλ μμ ― λ°°μΉλ₯Ό μμ λ‘κ² μ‘°μ ν λ μ μ©ν©λλ€.
π§ μ£Όμ κΈ°λ₯
- 컀μ€ν μ΄λ²€νΈ 체μΈμΌλ‘ μμΉ μ μ΄
- position: absoluteμ left/top μμ± λ³κ²½μ ν΅ν μ΄λ
- 컀μ μ€νμΌ λ³κ²½ λ° κ²½κ³μ ννΈ μΆκ° κ°λ₯
document.addEventListener('mousemove', (e) => {
if (isDragging) {
box.style.left = `${e.pageX - offsetX}px`;
box.style.top = `${e.pageY - offsetY}px`;
}
});
π λ°μν & μ κ·Όμ± κ³ λ €
- λͺ¨λ°μΌ λμμ μν΄ touchstart, touchmove μ΄λ²€νΈλ λ³ν μ²λ¦¬
- ν€λ³΄λ νμ κ°λ₯ν ꡬ쑰μ μκ°μ νΌλλ°±μ ν΅ν΄ μ κ·Όμ± κ°ν
- μν μ μ₯μ μν΄ localStorageμ μ°λνμ¬ UX μ§μμ± ν보
π κ²°λ‘
λλκ·Έ μ€ λλ‘ UIλ μ¬μ©μ μΈν°λμ μ κ°ννλ©΄μλ
UXλ₯Ό λ§€λλ½κ² λ§λ€ μ μλ μ€μν κΈ°λ₯μ λλ€.
λΌμ΄λΈλ¬λ¦¬μ μμ‘΄νμ§ μκ³ μμ μλ°μ€ν¬λ¦½νΈλ‘ ꡬννλ€λ©΄
μ¬μ¬μ©μ±κ³Ό νμ₯μ±κΉμ§ ν보ν μ μμ΅λλ€.
μ΄ κΈμ μ¬λ‘λ€μ νμ©ν΄
μ¬λ¬λΆμ νλ‘μ νΈμλ
μμ°μ€λ¬μ΄ λλκ·Έ μ€ λλ‘ UIλ₯Ό μ μ©ν΄ 보μΈμ.