CSS&JS/⚡Thinkers

(vanilla JS) touch event로 snap 되는 grab slider 만들기

arancia_ 2021. 7. 13. 16:14

mdn 터치 이벤트
https://developer.mozilla.org/ko/docs/Web/API/Touch_events

 

 

보통 많이 쓰는 슬라이더인 swiper의 기능중 하나를 vanilla javaScript로 구현해보았다.

  1. 터치 환경에서만 동작
    (웹에서 확인하려면 크롬기준 F12 > Toggle Device Toolbar(ctrl shift m)으로 확인해주세요)
  2. 터치하여 이동하는 동안(touchmove) 슬라이더가 transform의 translateX 값으로 움직입니다.
    (예전에 만들었던 바닐라 자바스크립트 터치 슬라이더(링크)는 움직이는 모습이 보이지 않았죠)
  3. 터치가 끝나면(touchend) 슬라이더를 감싸고 있는 부모의 좌측에 snap 됩니다.

 

성격 급한 사람은 샘플코드를 다운받으세요

touch (swiper).zip
0.00MB

 

 

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>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
    <title>swiper 대신</title>
<link href="touch_swiper.css" rel="stylesheet" type="text/css"/>
<script src="touch_swiper.js" defer></script>
</head>
<body>
 
<div id="wrapper">
    <ul id="swiper">
        <li>0</li>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
</div>
 
</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
@charset "utf-8";
 
*{margin:0;padding:0;box-sizing:border-box;}li{list-style-type:none;}
html,body{
    display:flex;flex-wrap:wrap;
    flex-direction:column;
    justify-content:center;
    overflow-x:hidden;
    width:100%;min-height:100vh;
    background:#000;}
 
#wrapper{
    position:relative; overflow:hidden;
    margin:0 auto;
    height:50vh;
    aspect-ratio:1.5 / 1;
    border:1px solid red;
}
 
#swiper{
    display:flex;flex-wrap:nowrap;
    position:relative; 
    cursor:grab;
    transition:all .1s;
}
 
#swiper li{
    display:flex;
    justify-content:center;
    align-items:center;
    flex:none;
    position:relative;
    height:50vh;
    aspect-ratio:1/1;
    background:#fff;
    border:1px solid #000;
    font-size:5vw;
    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
const wrapper = document.getElementById('wrapper');
const swiper = document.getElementById('swiper');
let left_wrap = wrapper.getBoundingClientRect().left;
let hei = wrapper.offsetHeight;
let len = swiper.children.length;
let ul_wid = hei * len;
let per = hei / (window.innerHeight / 20);
let pos = {
    prev : 0,
    now : 0,
    ul : 0
}
let order;
 
window.addEventListener('resize',()=>{
    left_wrap = wrapper.getBoundingClientRect().left;
    hei = wrapper.offsetHeight;
    ul_wid = hei * len;
    per = hei / (window.innerHeight / 20);
});
 
wrapper.addEventListener('touchmove',startSlider,false);
wrapper.addEventListener('touchend',adjustSlider,false);
 
function startSlider(e){
    e = e || window.event;
    e.preventDefault();
    // console.log(e.changedTouches[0]);
    pos.prev = e.changedTouches[0].clientX - left_wrap;
    if(pos.prev > pos.now){
        // console.log('오른쪽으로');
        pos.ul += per;
    }else{
        // console.log('왼쪽으로');
        pos.ul -= per;
    }
    moveSlider();
    pos.now = pos.prev;
 
}
 
function moveSlider(){
    swiper.style.transform = `translateX(${pos.ul}px)`;
}
 
function adjustSlider(){
    order = Math.round(pos.ul / hei);
    pos.ul = order * hei;
    if(pos.ul > 0){pos.ul = 0;}
    if(pos.ul < -(ul_wid - hei)){pos.ul = -(ul_wid - hei);}
    moveSlider();
}
cs