JAVASCRIPT -

Drag & Drop Vanilla Javascript(JS 드래그 앤 드롭)

  • -

Drag & Drop Vanilla Javascript(JS 드래그 앤 드롭)

안녕하세요 TriplexLab 입니다. 🧑‍🎄🧑‍🎄

오늘은 다음과 같이 Vanilla Javascript로 Drag & Drop기능에 관해서 살펴보도록 하겠습니다.

Drag & Drop Vanilla Javascript

👉HTML

<body>
    <div class="container">
        <div class="draggable" draggable="true">
            <span class="ico-drag"></span>
            <div class="el">HTML</div>
        </div>
        <div class="draggable" draggable="true">
            <span class="ico-drag"></span>    
            <div class="el">CSS</div>
        </div>
        <div class="draggable" draggable="true">
            <span class="ico-drag"></span>
            <div class="el">JavaScript</div>
        </div>
    </div>

    <div class="container">
        <div class="draggable" draggable="true">
            <span class="ico-drag"></span>
            <div class="el">React</div>
        </div>
        <div class="draggable" draggable="true">
            <span class="ico-drag"></span>
            <div class="el">Vue</div>
        </div>
        <div class="draggable" draggable="true">
            <span class="ico-drag"></span>
            <div class="el">Next JS</div>
        </div>
    </div>
</body>

 

👉CSS

body, div {
    margin: 0;
}

.container {
    background-color: #f3f5f7;
    padding: 2rem;
    border-collapse: collapse;
}
.container:nth-child(n+2){
    margin-top: 1rem;
}

.draggable {
    height: 82px;
    line-height: 82px;
    padding: 0 20px;
    background-color: white;
    border: 1px solid #c5cdd7;
    border-bottom:none;
    box-sizing: border-box;
    cursor: move;
}
.draggable:last-child {
    border-bottom: 1px solid #c5cdd7;
}

.draggable.dragging {
    opacity: .5;
    border: 2px dashed red;
}

.el {
    display: inline-block;
    vertical-align: middle;
}
.ico-drag {
    display: inline-block;
    vertical-align: inherit;
    width: 15px;
    height: 15px;
    background: url(./menu.png) no-repeat center top;
    background-size: cover;
}

👉JavaScript

다 같이 살펴보면 좋은것은 다음과 같은 함수 입니다👇👇
다음 함수의 역할은 쉽게 설명하면 하나의 Element를 마우스드레그를 하고, 이후에 어떤 Element를 인지 가져오는 함수 입니다.

이벤트가 발생할때 
getDragAfterElement(컨테이너Element, 수직 좌표) 함수에 각각의 2개 인자를 넘겨주고
draggableElements은 .draggable클래스에 .dragging라는 클래가 없는 엘리머트를 모두 배열로 가져오는것입니다.

draggableElements을 reduce로 루프를 돌려, 수직 좌표 - top값 - height값 / 2의 연산을 통해서 offset변수에 할당하였고
(예외 처리) 0 이하 와, 음의 무한대 사이에 Element를 리턴하는것 입니다.

결국에는 getDragAfterElement함수는 내가 마우스 드래그하고 마지막 위치해놓은 Element를 리턴하는것 입니다.

function getDragAfterElement(container, y) { //마지막 위치해놓은 Element를 리턴하는 함수
	const draggableElements = [...container.querySelectorAll('.draggable:not(.dragging)')]

	return draggableElements.reduce((closest, child) => {
		const box = child.getBoundingClientRect()  //해당 엘리먼트에 top값, height값 담겨져 있는 메소드를 호출해 box변수에 할당
		const offset = y - box.top - box.height / 2  //수직 좌표 - top값 - height값 / 2의 연산을 통해서 offset변수에 할당
		if (offset < 0 && offset > closest.offset) {  // (예외 처리) 0 이하 와, 음의 무한대 사이에 조건
			return { offset: offset, element: child } // Element를 리턴
		} else {
			return closest
		}
	}, { offset: Number.NEGATIVE_INFINITY }).element
};
containers.forEach(container => {
    container.addEventListener('dragover', e => {
        e.preventDefault()
        const afterElement = getDragAfterElement(container, e.clientY); //(결국 드래그하여 마지막 영역의 엘리먼트를 반환합니다.)
        const currentDraggable = document.querySelector('.dragging'); //현재 내가 잡은 엘리먼트
        container.insertBefore(currentDraggable, afterElement); //마지막까지 드래그한 엘리먼트 앞에 현재 내가 잡은 엘리먼트를 삽입 합니다.
    })
});

👉전체 소스코드(JS)

(() => {
    const $ = (select) => document.querySelectorAll(select);
    const draggables = $('.draggable');
    const containers = $('.container');

    draggables.forEach(el => {
        el.addEventListener('dragstart', () => {
            el.classList.add('dragging');
        });

        el.addEventListener('dragend', () => {
            el.classList.remove('dragging')
        });
    });

    function getDragAfterElement(container, y) {
        const draggableElements = [...container.querySelectorAll('.draggable:not(.dragging)')]
      
        return draggableElements.reduce((closest, child) => {
          const box = child.getBoundingClientRect() //해당 엘리먼트에 top값, height값 담겨져 있는 메소드를 호출해 box변수에 할당
          const offset = y - box.top - box.height / 2 //수직 좌표 - top값 - height값 / 2의 연산을 통해서 offset변수에 할당
          if (offset < 0 && offset > closest.offset) { // (예외 처리) 0 이하 와, 음의 무한대 사이에 조건
            return { offset: offset, element: child } // Element를 리턴
          } else {
            return closest
          }
        }, { offset: Number.NEGATIVE_INFINITY }).element
    };

    containers.forEach(container => {
    	container.addEventListener('dragover', e => {
            e.preventDefault()
            const afterElement = getDragAfterElement(container, e.clientY); //(결국 드래그하여 마지막 영역의 엘리먼트를 반환합니다.)
            const currentDraggable = document.querySelector('.dragging'); //현재 내가 잡은 엘리먼트
            container.insertBefore(currentDraggable, afterElement); //마지막까지 드래그한 엘리먼트 앞에 현재 내가 잡은 엘리먼트를 삽입 합니다.
        })
    });
})();

👉 전체 소스코드

전체 소스코드를 github에도 공유합니다.🔥👍✅👏🎉

 

GitHub - younhoso/younhoso

Contribute to younhoso/younhoso development by creating an account on GitHub.

github.com

👉 참고 자료

drag - web API

Web Dev Simplified

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.