• 구글 계정 로그인

jquery drag & drop

페이지 정보

profile_image
작성자 LJM
댓글 0건 조회 222회 작성일 23-10-29 00:17

본문

순수하게 자바스크립트, 제이쿼리로 드래그 앤 드롭 기능을 만들었는데 많은 공부가 되어서 정리한다.

나의 경우 2가지 div 박스에 여러 개의 li를 드래그 앤 드롭했다.

▼ 간단한 HTML 예시

<div id="div1" class="box">
<ul id="ul1" class="ul">
 <li id="li1" class="list">li 1</li>
 <li id="li2" class="list">li 2</li>
 <li id="li3" class="list">li 3</li>
</ul>
</div>
<div id="div2" class="box">
<ul id="ul2" class="ul">
</ul>
</div>
 

1. 드래그 앤 드롭은 '드래그할 대상'과 '드롭될 대상' 2가지가 필요하다.
'드래그할 대상'과 대상'에는 자바스크립트를 이용해 각각 아이디로 이벤트 리스너를 걸어준다.

클래스 네임으로는 이벤트가 안 걸려서 선택됐을 때 각각 아이디가 있어야 한다.

또한, 드래그할 대상에는 draggable을 추가해주어야 한다.

▼ 이벤트 리스너 추가 및 draggable 토글 되는 자바스크립트

$(document).ready(function(){
// li에 이벤트 추가
for(var i = 1 ; i <= 3 ; i++){
 var id = 'li'+i;
 document.getElementById(id).addEventListener('dragstart', dragstart);
 document.getElementById(id).addEventListener('drag', drag);
 document.getElementById(id).addEventListener('dragend', dragend);
}

// div에 이벤트 추가
for(var i = 1 ; i <= 2 ; i++){
 var id = 'div'+i;
 document.getElementById('div1').addEventListener('dragenter', dragenter);
 document.getElementById('div1').addEventListener('dragover', dragover);
 document.getElementById('div1').addEventListener('drop', drop);
 document.getElementById('div1').addEventListener('dragleave', dragleave);
}
   
// 선택된 li에 draggable = true & 선택 해제 된 li에 draggable = false
$('ul').on('click','li',function(){
 $(this).toggleClass('selected');
 if($(this).is('.selected')){
  $(this).attr('draggable',true);
 } else {
  $(this).attr('draggable',false); 
 }
});
});
 

2. 드래그할 대상을 선택해서 드롭이 될 때까지 여러 가지 순서를 거친다.
2번째 코드 블록에도 적어놨듯이 각 이벤트는 드래그할 대상(li) 또는 드롭될 대상(div)에 구분해서 걸어야 한다.

이렇게 구분해야 하는 이유는 각 이벤트가 발생할 때 타깃의 위치 등 파라미터의 기준이 다르기 때문이다.

 

A. 드래그할 대상

(1) dragstart : 드래그할 대상을 잡고 움직이기 시작할 때 이벤트가 발생한다.

(4) drag : 마우스가 드래그 할 대상을 놓지 않고 잡고 있을 때 계속 발생한다.

(7) dragend : 모든 드래그와 드롭이 끝났을 때 발생한다.

 

B. 드롭될  대상

(2) dragenter : 마우스가 드롭될 대상 경계에 진입될 때 이벤트가 발생한다.

(3) dragover : 마우스가 드롭될 대상 위에 머무를 때 계속 발생한다.

(5) drop : 마우스가 드래그할 대상을 드롭했을 때 발생한다.

(6) dragleave : 마우스가 드롭될 대상을 벗어났을 때 발생한다.

 

이 외에도 관련 이벤트가 많은데 나는 저 7개만 사용했다.

 

3. 각 이벤트에 대해
(1) dragstart

드래그를 하기 위해 마우스가 눌린 상태에서 움직이기 시작할 때 발생하는 이벤트로 드래그될 대상의 html을 저장했다.

나의 경우 크롬과 IE에서 모두 다 잘 돌아가야 했다.

크롬의 경우, 드롭할 데이터를 저장해 두는 dataTransfer.setData의 형식이 다양하고 드래그 시 반투명하게 보이는 미리 보기 이미지(ghost image)와 같이 지원해주는 기능이 많았다.

반면, IE는 안 되는 것이 많았고 기능도 단순했기 때문에 IE에 맞춰야만 했다.

드래그 시작 시 드래그될 대상의 정보를 dataTransfer에 담고 해당 대상들은 숨겨지도록 했다.

function dragstart(e){
var html = '';
$('.selected').each(function(){
 html += '<li class="list" id = "' + $(this).attr('id') + '">' + $(this).html() + '</li>';
});
   
// 드래그 될 li들의 html을 텍스트 형태로 dataTransfer에 세팅
e.dataTransfer.setData('text',html);
}
 

(2) dragenter

드롭될 대상의 경계에 진입하는 순간 발생하는 이벤트로 주로 시작적인 효과를 나타내도록 했다.

또한, 드래그할 때 특정 위치에서 스크롤을 적용하기 위해 위치 값을 구했다.

드롭하는 과정에서 원치 않는 이벤트를 막고 순수하게 드롭만 할 수 있도록 e.preventDefault()를 작성하였다.

var targetBox = ''; // 현재 선택된 div
var topPos = ''; // top 위치
var bottomPos = ''; // bottom 위치
var leftPos = ''; // left 위치
var rightPos = ''; // right 위치

function dragenter(e){
// 브라우저 표준동작 취소
e.preventDefault();
   
// 선택된 div 표시
targetBox = $(e.target).closest('.box').attr('id');
$('#'+targetBox).addClass('selectedBox');
   
// div 위치
topPos = document.getElementById(targetBox).getBoundingClientRect().top;
bottomPos = topPos + $('#'+targetBox).height();
leftPos = document.getElementById(targetBox).getBoundingClientRect().left;
rightPos = leftPos + $('#'+targetBox).width();
}
 

(3) dragover

드롭될 대상의 위에 머무르는 동안 계속 발생하는 이벤트로 스크롤과 위치 미리보기를 작성했다.

function scroll(target, step){
 // 현재 스크롤의 세로 위치
var scrollY = $('#' + target).scrollTop();
$('#' + target).scrollTop(scrollY + step);
if(!scrollStop){
 setTimeout(function(){ scroll(step) },3);
}
}

function dragover(e){
e.preventDefault();
   
//top border의 ±10px안에 있을 때 위로 스크롤
if(e.clientY < topPos + 10 && e.clientY > topPos - 10){
 scrollStop = false;
 scroll(targetBox, -10);
}
   
// bottom border의 ±10px안에 있을 때 아래로 스크롤
else if(e.clientY < bottomPox + 10 && e.clientY > bottomPos - 10){
 scrollStop = false;
 scroll(targetBox, 10);
}
   
// li 사이에 있을 때 위치 미리보기
else if($(e.target).is('.list, .preview')){
 var html = '<div class="preview"></div>' + $(e.target).closest('.list').html();
 $(e.target).closest('.list').html(html);
}
}
 

(4) drag

드래그 시작 후 드롭되기 전까지 계속 발생하는 이벤트로 드래그할 대상을 안 보이게 했다.

function drag(e){
$('.selected').hide();
scrollStop = true;
}
 

(5) drop

마우스를 누르고 있던 것을 떼고 드롭했을 때 발생하는 이벤트다.

단, 제대로 된 대상이 아니더라도 마우스를 떼는 순간 드롭이 되기 때문에 드롭되는 대상을 구분해야 한다.

또한 li가 아니더라도 drop 이벤트를 걸어줬기 때문에 li 외에 드롭되지 못하도록 해야 한다.

function drop(e){
e.preventDefault();
   
// 드래그 시작 시 저장했던 li html을 가져온다.
var html = e.dataTransfer.getData('text');
   
// li만 드롭
if(html.match('selected')){
 if($(e.target).is('.box')){ // li 맨 아래에 
  $('#'+targetBox).find('.ul').append(html);
  $('.selected').each(function(){ // 기존의 li 삭제 
   $(this).remove();
  });
   
 } else if($(e.target).is('.preview')){ // li 사이에
  $('.preview').parent().before(html);
  $('.selected').each(function(){ // 기존의 li 삭제 
   $(this).remove();
  });
  
 } else { // 잘못 드롭 됐을 때
  $('.selected').trigger('click');
  $('.selected').show();
 }
  
} else {
 $('.preview').remove();
 $('.selectedBox').removeClass('selectedBox');
 return;
}
}
 

(6) dragleave

드롭될 대상 밖으로 벗어났을 때 발생하는 이벤트다.

dragenter에서 구했던 div의 위치를 기준으로 벗어났는지 벗어나지 않았는지 체크했다.

function dragleave(e){
$('.preview').remove(); // 미리보기 지우기

if(e.clientY > bottomPos || e.clientY < topPos || e.clientX < leftPos || e.clientX > rightPos){
 $('.selectedBox').removeClass('selectedBox');

}
 

(7) dragend

모든 드래그 앤 드롭이 끝났을 때 발생하는 이벤트로 초기화한다.

function dragend(e){
scrollStop = true;
$('.selected').show();
$('.preview').remove();
$('.selectedBox').removeClass('selectedBox');
}
 

4. 마치며
정리본으로 옮겨 쓰면서 변수명을 모두 다 바꾸고 생략한 것이 많기 때문에 직접 코드로 돌렸을 때 돌아가지 않을 수도 있고 엉성한 것도 많을 것입니다. 참고용으로만 보시길 바라며 비난 외의 모든 댓글은 환영합니다. :)

댓글목록

등록된 댓글이 없습니다.