CSS&JS/⚡Thinkers

[vanilla JS] transform으로 드래그 시키기 (client 기준)

arancia_ 2021. 9. 1. 17:38

https://ko.javascript.info/mouse-drag-and-drop

 

드래그 앤 드롭과 마우스 이벤트

 

ko.javascript.info

보통 vanilla JavaScript로 dom을 드래그 시키려고 할 때 top,left 값을 수정한다.
킹치만 그렇게 하면 layout 단계까지 전부 건들기 때문에 느려질 수 있다...

그러므로

  • paint 단에서 전부 처리 가능한 transform값으로 dom을 드래그 시켜보자
  • onmousedown 이런 직접 할당 방식이 아니라, addEventListener 이벤트 핸들러 방식으로 작성할것이다.
  • ! 재사용 ! 이 가능하도록 특정 함수 안에 dom만 넣어주면 모든것이 처리되게끔 만들어볼거다.

 

 

 

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>drag</title>
<link href="./style.css" rel="stylesheet" type="text/css"/>
<script src="main.js" defer></script>
</head>
<body>
<!-- https://ko.javascript.info/mouse-drag-and-drop -->
 
    <section id="test_1" class="draggable" data-x="0" data-y="0">
        <article class="drag__head"><p>001</p></article>
        <article class="drag__body">
            <p>Lorem ipsum dolor sit amet.</p>
            <p>Lorem ipsum dolor sit amet.</p>
            <p>Lorem ipsum dolor sit amet.</p>
            <p>Lorem ipsum dolor sit amet.</p>
            <p>Lorem ipsum dolor sit amet.</p>
            <p>Lorem ipsum dolor sit amet.</p>
            <p>Lorem ipsum dolor sit amet.</p>
            <p>Lorem ipsum dolor sit amet.</p>
            <p>Lorem ipsum dolor sit amet.</p>
            <p>Lorem ipsum dolor sit amet.</p>
            <p>Lorem ipsum dolor sit amet.</p>
        </article>
    </section>
 
    <section id="test_2" class="draggable" data-x="0" data-y="0">
        <article class="drag__head"><p>002</p></article>
        <article class="drag__body">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod ut a, at eaque voluptate autem!
        </article>
    </section>
 
    <section id="test_3" class="draggable" data-x="0" data-y="0">
        <article class="drag__head"><p>003</p></article>
        <article class="drag__body">
            <p>Lorem ipsum dolor sit amet.</p>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, harum!</p>
        </article>
    </section>
    
</body>
</html>
cs



CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@charset "utf-8";
*{margin:0;padding:0;box-sizing:border-box;}
html,body{
    overflow:hidden;
    width:100%;height:100vh;
    background:#eee;
}
 
.draggable{
    position:fixed;
    top:0;left:0;
}
 
.drag__head{
    position:relative;
    width:100%;
    padding:2rem 0;
}
.drag__head > p{
    position:relative;
    padding:1rem;
    background:black;
    color:#fff;
    cursor:move;
    user-select:none;}
 
    .drag__head > p::after{
        content:'';display:block;position:absolute;
        top:100%;left:0;
        width:calc(100% - 2px);height:2rem;
        background:#fff;
        border:1px solid #d2d2d2;
    }
 
.drag__body{
    position:relative;
    padding:2rem; padding-top:0;
    background:#fff;
    border:1px solid #d2d2d2; border-top:none;
}
cs



JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
let dragAble = false;
 
function make_drag(dom){
    const dragHead = dom.querySelector('.drag__head');
    dragHead.addEventListener('mousedown',(e)=>{start_drag(e,dom)});
    dragHead.addEventListener('mousemove',(e)=>{on_drag(e,dom)});
    dragHead.addEventListener('mouseup', ()=>{stop_drag(dom)});
    dom.addEventListener('mouseleave', ()=>{stop_drag(dom)});
    
}//make_drag
 
function start_drag(e,dom){
    dragAble = true
    dom.style.zIndex = 1000;
    dom.dataset.x = e.clientX - dom.getBoundingClientRect().left; 
    dom.dataset.y = e.clientY - dom.getBoundingClientRect().top;
    // console.log(e.clientX, dom.getBoundingClientRect().left, dom.dataset.x);
}//start_drag
 
function stop_drag(dom){
    dragAble = false;
    dom.style.zIndex = "auto";
    dom.dataset.x = dom.getBoundingClientRect().left; 
    dom.dataset.y = dom.getBoundingClientRect().top; 
}//stop_drag
 
function on_drag(e,dom){
    if(!dragAble){return;}
    e = e || window.event;
 
    const posX = e.clientX - dom.dataset.x;
    const posY = e.clientY - dom.dataset.y;
 
    const nowX = posX >= 0 ? posX : 0;
    const nowY = posY >= 0 ? posY : 0;
 
    // console.log(e.clientX, dom.dataset.x, nowX);
    dom.style.transform = `translate(${nowX}px,${nowY}px)`;
}//on_drag
 
/* 실행 */
const test_1 = document.getElementById('test_1');
const test_2 = document.getElementById('test_2');
const test_3 = document.getElementById('test_3');
 
make_drag(test_1);
make_drag(test_2);
make_drag(test_3);
cs

 

그간 나온 예제들이 대부분 onmouseup = null 식으로 처리를 하는데 이렇게 하다보면 너무 복잡해져서 대체 어떻게 해야 이벤트핸들러로 드래그를 처리할 수 있을까 실패를 겁나 많이 했다 ㅎ...
그러던 와중 노마드코더(니코 쌤)의 바닐라자바스크립트와 canvas로 그림판 만들기 예제 강의를 들으면서 flag 값의 참/거짓 상태에 따라 ok하는것에서 결정적인 힌트를 얻었다. 힌트도 아니지 그냥 그방식으로 짰습니다 ㅋㅋㅋ ㅠ.ㅠ 고마워요 니코쌤....

제이쿼리 공식 플러그인에도 drag을 제공한다.
만일 바닐라자바스크립트가 골치가 썩는다면 제이쿼리 draggable을 사용해도 좋다...