CSS&JS/⚡Thinkers

[vanilla JS] 위 아래 버튼으로 list의 순서 바꾸기

arancia_ 2021. 9. 27. 11:11
위 아래 버튼으로, 한 parent DOM의 child element들의 순서를 바꾸고 싶다

기본 jquery에는 Sortable 이라는 효과를 내되, 마우스 드래그가 아니라 좀 더 단순하게!
내가 선택한 dom을 직속 부모 기준으로 순서를 바꿀 수 있다면 어떨까?

우선 깃허브 구현 :
https://ohikmyeong.github.io/customUpDown/ 

 

change list order

 

ohikmyeong.github.io

 

 

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>change list order</title>
<link rel="stylesheet" type="text/css" href="./css/style.css"/>
<script src="./js/main.js" defer></script>
</head>
<body>
    
<section class="dom">
    <article class="btns__dom">
        <button class="btn_up"><span>위로</span></button>
        <button class="btn_down"><span>아래로</span></button>
    </article><!-- btns__dom -->
 
    <ul class="ul__dom">
        <li><div class="txt">000_aaa</div></li>
        <li><div class="txt">111_bbb</div></li>
        <li><div class="txt">222_ccc</div></li>
        <li><div class="txt">333_ddd</div></li>
        <li><div class="txt">444_eee</div></li>
    </ul><!-- ul__dom -->
</section><!-- dom -->
    
<section class="dom">
    <article class="btns__dom">
        <button class="btn_up"><span>위로</span></button>
        <button class="btn_down"><span>아래로</span></button>
    </article><!-- btns__dom -->
 
    <ul class="ul__dom">
        <li><div class="txt">000_aaa</div></li>
        <li><div class="txt">111_bbb</div></li>
        <li><div class="txt">222_ccc</div></li>
        <li><div class="txt">333_ddd</div></li>
        <li><div class="txt">444_eee</div></li>
    </ul><!-- ul__dom -->
</section><!-- dom -->
 
</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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@charset "utf-8";
*{margin:0;padding:0;box-sizing:border-box}
li{list-style-type:none;}
button{font-family:inherit;font-size:inherit;}
 
html,body{
    display:flex;flex-flow:column nowrap;
    justify-content:center;
    align-items:center;
    width:100%;min-height:100vh;
    background:#ccc;}
 
.dom{
    position:relative;
    width:100%;max-width:400px;
    margin:1rem auto; padding:2rem; padding-top:0;
    border:1px solid #d2d2d2;
    background:whitesmoke;}
 
.btns__dom{
    display:flex;flex-flow:row wrap;
    justify-content:center;align-items:center;
    position:relative;
    width:100%;    
    padding:1em;}
 
.btns__dom button{
    display:block;
    padding:.5em 2em; margin:5px;
    background:rgb(33, 26, 92);
    border:none;
    color:whitesmoke;
    cursor:pointer;}
 
    .btns__dom button:hover{filter:brightness(200%);}
 
.btns__dom button span{pointer-events:none;}
 
.ul__dom{
    position:relative; overflow-y:auto;
    width:100%;aspect-ratio:1/2;
    background:#eee;
    border:1px solid #d2d2d2;}
 
    .ul__dom li{
        position:relative;
        width:100%;
        padding:2em 1em;
        background:white;
        border-bottom:1px solid #d2d2d2;
        cursor:pointer;}
 
    /* 선택시 */
    .ul__dom li.on{
        background:cornflowerblue;
        font-weight:bold;color:whitesmoke;
        box-shadow:inset .5rem .5rem 1rem rgba(53, 56, 233, 0.5);}
 
.ul__dom li .txt{
    position:relative;
    pointer-events: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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
(function(){
    const doms = document.getElementsByClassName('dom');
    for(let dom of doms){
        dom.addEventListener('click', on_click_dom);
    }
})();
 
function on_click_dom(e){
    e = e || window.event;
    const target = e.target;
    switch(target.tagName){
        case "LI" :
            add_on_li(target);
            break;
        case "BUTTON" :
            set_up_down(target);
            break;
        default :
            break;
    }//switch
}//on_click_dom
 
function add_on_li(target){
    if(!target){return;}
    const parent = target.parentElement;
    const all_child = parent.children;
    const siblings = Array.prototype.filter.call(all_child, li => li != target);
    
    for(let li of siblings){li.classList.remove('on');}
 
    target.classList.toggle('on');
}//add_on_li
 
function set_up_down(target){
    //선택된 li가 없으면 early return
    const this_ul = target.parentElement.nextElementSibling;
    const all_li = this_ul.children;
    const liON = this_ul.getElementsByClassName('on')[0];
    if(!liON){return}
 
    //선택된 li의 index를 가져온다.
    const idx = get_li_idx(all_li,liON);
 
    //복사한 li
    const copyLI = copy_li_on(liON);
 
    //선택한 버튼에 따라 복사하고
    const final_idx = apply_li_on(target,idx,all_li,copyLI);
 
    //원본은 지운다
    delete_original(final_idx,liON,this_ul);
 
    //li.on 다시 붙임
    add_on_li(all_li[final_idx]);
 
}//set_up_down
 
function get_li_idx(all_li,liON){
    const li_idx = Array.prototype.indexOf.call(all_li, liON);
    return li_idx;
}//get_li_idx
 
function copy_li_on(liON){
    const copyLI = document.createElement('LI');
    copyLI.innerHTML = liON.innerHTML;
    return copyLI;    
}//copy_li_on
 
function apply_li_on(target,idx,all_li,copyLI){
    if(target.classList.contains('btn_up')){
        const final_idx = idx - 1;
        if(final_idx < 0){return;}
        all_li[final_idx].before(copyLI);
        return final_idx;
    }else{
        const final_idx = idx + 1;
        if(final_idx >= all_li.length){return;}
        all_li[final_idx].after(copyLI);
        return final_idx;
    }//if
}//apply_li_on
 
function delete_original(final_idx,liON,this_ul){
    if(final_idx == undefined || final_idx == null){return;}
    this_ul.removeChild(liON);
}//delete_original
cs