728x90
안녕하세요. 이전에 자바스크립트로 drag&drop을 구현해본 적 있는데요, 오늘은 테이블의 row를 drag&drop으로 옮기는 것을 구현해보려고 합니다.
dragableTable.html
<table>
<thead>
<tr>
<th>이름</th>
<th>나이</th>
<th>성별</th>
</tr>
</thead>
<tbody>
<tr id="1">
<td>홍길동</td>
<td>20</td>
<td>남</td>
</tr>
<tr id="2">
<td>이순신</td>
<td>35</td>
<td>남</td>
</tr>
<tr id="3">
<td>유관순</td>
<td>17</td>
<td>여</td>
</tr>
<tr id="4">
<td>강감찬</td>
<td>45</td>
<td>남</td>
</tr>
</tbody>
</table>
dragableTable.css
table {
padding:10px;
border-collapse: collapse;
width: 50%;
margin:auto;
}
th,
td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ddd;
}
/*옮길때 불투명으로 보이는 부분*/
tr.dragging {
opacity: 0.5;
}
dragableTable.js
// 드래그 앤 드롭을 위한 이벤트 리스너 등록
document.addEventListener('DOMContentLoaded', () => {
// tbody 요소의 모든 자식 요소 중 tr 요소를 선택하여 rows 변수에 할당
const rows = document.querySelectorAll('tbody > tr');
// rows에 forEach 메서드를 호출하여 각각의 tr 요소에 대해 드래그 이벤트 리스너를 등록
rows.forEach(row => {
// 드래그가 가능하도록 draggable속성을 true로 설정
row.draggable = true;
// 드래그 이벤트가 시작될 때 실행할 콜백 함수 등록
row.addEventListener('dragstart', e => {
//drag와 관련된 이벤트에서는 모두 DataTransfer 객체를 사용할 수 있다.
//dataTransfer 객체가 setData()함수를 제공.
//setData():데이터를 드래그할 때 전달하고자 하는 정보를 설정하는 메서드.
//첫 번째 인자로 데이터의 형식을 지정할 수 있으며, 두 번째 인자로 전달하려는 값(value)을 지정.
// setData 메서드를 호출하여 드래그 데이터 설정 - 데이터 형식은 text/plain, 값은 해당 tr 요소의 id 값.
//이렇게 설정된 드래그 데이터는 드래그 이벤트가 발생할 때 dataTransfer 객체에 저장되어 드롭 이벤트가 발생할 때 사용된다.
e.dataTransfer.setData('text/plain', row.id);
});
});
// tbody 요소에 드롭 이벤트 리스너 등록
const dropzone = document.querySelector('tbody');
dropzone.addEventListener('dragover', e => {
// 기본 이벤트 동작을 막음
e.preventDefault();
// 드래그된 요소를 드롭할 위치를 계산하는 함수를 호출하여 그 결과값을 afterElement 변수에 할당
const afterElement = getDragAfterElement(dropzone, e.clientY);
// dragging 클래스를 가진 요소를 선택하여 draggable 변수에 할당
const draggable = document.querySelector('.dragging');
// afterElement가 null일 경우, 마지막 자식 요소로 추가하고 그렇지 않은 경우, afterElement 바로 전 위치에 추가
if (afterElement == null) {
dropzone.appendChild(draggable);
} else {
dropzone.insertBefore(draggable, afterElement);
}
});
// 드롭 대상 행 중 이동할 위치를 결정하는 함수
function getDragAfterElement(container, y) {
// container 내의 모든 tr 요소들 중 dragging 클래스를 가지지 않은 요소들을 선택하여 draggableElements 변수에 할당
const draggableElements = [...container.querySelectorAll('tr:not(.dragging)')];
// draggableElements 배열을 reduce 메서드를 이용하여 y값에 따라 가장 근접한 요소를 찾아낸다.
return draggableElements.reduce((closest, child) => {
const box = child.getBoundingClientRect();
// 드래그 위치 - 드롭 대상 요소의 top 위치 - 드롭 대상 요소의 높이 / 2 값을 offset 변수에 할당
const offset = y - box.top - box.height / 2;
// offset 값이 음수이고 closest.offset보다 더 큰 경우, closest를 현재 child 요소로 대체
if (offset < 0 && offset > closest.offset) {
return { offset: offset, element: child };
} else {
return closest;
}
}, { offset: Number.NEGATIVE_INFINITY }).element;
// reduce 함수에서 초기 값으로 사용되는 객체.
//offset 속성은 "-Infinity"로 설정하여, reduce 함수가 실행되면서 만들어지는 첫 closest.offset 값이 항상 offset보다 크도록 보장한다.
}
// 드래그 중인 행의 스타일 설정.
//'dragging' 클래스는 드래그 중인 요소를 스타일링하기 위해 사용되므로 드래그가 종료되면 스타일링 제거
// 어떤 요소에서든지 드래그 이벤트가 발생하면 실행됨
document.addEventListener('dragend', e => {
// 'dragend' 이벤트가 발생한 요소 중 가장 가까운 <tr> 요소를 찾아서
const draggable = e.target.closest('tr');
// 해당 <tr> 요소의 'dragging' 클래스를 제거하기
draggable.classList.remove('dragging');
});
위 코드로 완성되면 아래와 같이 동작하는 것 확인 할 수 있습니다.
-자세한 내용은 아래 링크 참고 바랍니다.
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragstart_event
https://developer.mozilla.org/ko/docs/Web/API/HTMLElement/dragend_event
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragover_event
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
https://developer.mozilla.org/ko/docs/Web/API/Element/getBoundingClientRect
https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/setData
'JavaScript' 카테고리의 다른 글
[JavaScript] 정규식을 활용하여 이메일 로그인 시 예외처리하기 (0) | 2023.05.08 |
---|---|
[JavaScript] 내 화면 녹화 및 다운로드하기 (0) | 2023.05.04 |
[JavaScript] 두 개의 range slider로 최소/최대 지정하기 (0) | 2023.04.21 |
[ javascript ] EJS 사용해서 서버가 보낸 값 출력하기 (0) | 2023.04.14 |
[JavaScript]i18next을 활용한 언어 변환 처리 (0) | 2023.04.08 |