CSS&JS/👀Study and Copy

WDS- Sortable Drag & Drop List

arancia_ 2022. 8. 9. 15:14

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
<!DOCTYPE html>
<html lang="ko">
<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>How To Build Sortable Drag & Drop With Vanilla Javascript</title>
    <link rel="stylesheet" type="text/css" href="./css/style.css">
    <script src="js/main.js" type="module"></script>
</head>
<body>
    <ul class="container">
        <li class="draggable" draggable="true">Hello</li>
        <li class="draggable" draggable="true">World</li>
        <li class="draggable" draggable="true">Nice</li>
    </ul>
 
    <ul class="container">
        <li class="draggable" draggable="true">To</li>
        <li class="draggable" draggable="true">Meet</li>
        <li class="draggable" draggable="true">You</li>
    </ul>
</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
@charset "utf-8";
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@500;600&display=swap');
:root{
    --sans-serif:'Poppins';
}
 
*{margin:0;padding:0;box-sizing:border-box;}
 
html,body{
    width:100%; min-height:100vh;
    font-family:var(--sans-serif), sans-serif; font-size:20px;
}
 
.container{
    position:relative;
    width:90%;
    padding:1rem 2rem; margin:1rem auto;
    background:rgb(56, 56, 72);
}
 
.draggable{
    list-style-type:none;
    margin:1rem 0; padding:1rem 2rem;
    background:#e5e9ef;
    border-radius:.5rem;
    cursor:move;
    box-shadow:
        inset 4px 4px 10px 5px #fff,
        inset -1px -1px 5px 10px rgba(0,0,0,.1),
        2px 2px 0 rgba(0,0,0,1),
        5px 5px 0 rgba(0,0,0,1),
        10px 10px 0 rgba(0,0,0,1);
}
 
.dragging{filter:brightness(60%); opacity:.5;}
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
const $$drag = document.querySelectorAll('.draggable');
const $$container = document.querySelectorAll('.container'); 
 
$$drag.forEach($drag => {
    $drag.addEventListener('dragstart',()=>{
        toggle_dragging($drag,true);
    });
 
    $drag.addEventListener('dragend',()=>{
        toggle_dragging($drag,false);
    });
});
 
$$container.forEach($container=>{
    $container.addEventListener('dragover',(e)=>{
        e.preventDefault(); //금지 커서 없앰
        const {element : $after} = get_drag_after_elem($container, e.clientY);
        const $drag = document.querySelector('.dragging');
        // console.log($after);
 
        if(!$after){
            $container.appendChild($drag);
        }else{
            $container.insertBefore($drag, $after)
        }
    });
});
 
/* toggle class "dragging" */
function toggle_dragging($drag,bool){$drag.classList.toggle('dragging',bool);}
 
/*  */
function get_drag_after_elem($contianer, y){
    const $$sib = [...$contianer.querySelectorAll('.draggable:not(.dragging)')];
    // console.log($$sib);
 
    return $$sib.reduce(($closest,$sib)=>{
        const {top, height} = $sib.getBoundingClientRect();
        const offset = y - top - height / 2;
        if(offset < 0 && offset > $closest.offset){
            return {offset: offset, element : $sib};
        }else{
            return $closest;
        }//if else
    },{offset : Number.NEGATIVE_INFINITY});//reduce
}//get_drag_after_elem
cs