자바스크립트

자바스크립트> 캐러셀에 스와이프 기능 만들기 (터치와 간편한라이브러리)

연습노트 2024. 7. 10. 11:32

 

터치되는 캐러셀같은거 조작해보면 대충 이런 기능이 들어있습니다.

기능1. 드래그한 거리만큼 사진도 왼쪽으로 움직여야함

기능2. 마우스 떼었을 때 일정거리 이상 이동했으면 사진2 보여줌, 아니면 다시 사진1 보여줌

기능1 부터 만들어봅시다. 

근데 이거 만들려면 알아야할 이벤트가 3개 있습니다.

 

mouse 이벤트 3개

 

마우스로 어떤 html 요소를 조작할 때 발동하는 이벤트가 있습니다.

mousedown (어떤 요소에 마우스버튼 눌렀을 때)

mouseup (어떤 요소에 마우스버튼 뗐을 때)

mousemove (어떤 요소위에서 마우스 이동할 때)

알아두면 유용합니다. 

 

 

설명하다
 
<div>캐러셀있는곳</div>

<script>
  $('.slide-box').eq(0).on('mousemove', function(){
    console.log('안녕')
  })
</script>

그래서 예를 들어 이렇게 코드짜면 .slide-box 위에 마우스 움직일 때 마다 '안녕'이 출력됩니다.

 

 

 

 

설명하다
 
<div>캐러셀있는곳</div>

<script>
  $('.slide-box').eq(0).on('mousemove', function(e){
    console.log(e.clientX)
  })
</script>

이게 더 유용한데 mouse어쩌구 이벤트리스너안에선 e.clientX e.clientY를 출력해볼 수 있는데 

현재 마우스 좌표를 알려줍니다. 유용하겠죠?

이거 쓰면 유저가 얼마나 사진을 드래그 했는지 그런 것도 알 수 있을듯 ㄷㄷ

 

 

 

 

 

 

 

기능1. 사진1을 왼쪽으로 드래그한 거리만큼 사진1도 왼쪽으로 움직여야함

 

예를 들어 사진1을 클릭하고 왼쪽으로 50px 잡아끌었다면

사진1도 왼쪽으로 50px 움직여야합니다.

근데 사진1만 움직이는거말고 사진3개 전부 담긴 큰 박스 움직이는게 좋을듯

 

 

 

이동거리를 어떻게 파악하죠?

마우스 누를 때의 X좌표 & 마우스 움직일 때의 X좌표를 빼보면 나오는거 아닙니까 초등학교 수학문제인듯 

빼보도록 합시다. 

 

 

 

설명하다
 
<div>캐러셀있는곳</div>

<script>
  $('.slide-box').eq(0).on('mousedown', function(e){
    e.clientX ← 이거랑
  });

  $('.slide-box').eq(0).on('mousemove', function(e){
    e.clientX ← 이거를 빼야할듯
  });
</script>

저거 e.clientX 두개 빼면 됩니다. 

근데 안타깝게도 모든 변수는 범위가 있어서 함수 바깥으로 탈출할 수 없습니다.

못뺄듯 

 

근데 함수 바깥에 있던 변수는 함수 안에서 맘대로 쓸 수 있습니다.

그래서 함수 바깥에 변수를 만들어두면 함수들끼리 변수 공유가 가능합니다.

그럼 뺄 수 있을듯 

 

 

 

 

설명하다
 
<script>
  var 시작좌표 = 0;

  $('.slide-box').eq(0).on('mousedown', function(e){
    시작좌표 = e.clientX;
  });

  $('.slide-box').eq(0).on('mousemove', function(e){
    console.log(e.clientX - 시작좌표)
  });
</script>

1. 시작좌표라는 변수를 함수들 바깥에 만들어둡니다. (그럼 모든 함수에서 이용가능)

2. 마우스 클릭시 현재 좌표를 var 시작좌표에 저장해줌

3. mousemove 이벤트발생시 var 시작좌표랑 현재좌표인 e.clientX를 빼봄

그걸 출력해보면 현재 드래그 이동거리가 잘 나오는군요

왼쪽으로 드래그하면 -100 이렇게 출력되고 오른쪽으로 드래그하면 100 이런거 출력되는듯  

이제 이동거리를 구했으니 "이동거리만큼 저거 박스도 이동해달라"고 코드짜오십시오.  

 

참고로 저렇게 모든지역에서 이용할 수 있는 변수들은 전역변수라고 합니다.

 

 

 

 

 

 

 

 

이동거리만큼 저거 박스도 이동해달라

 

설명하다
 
<script>
  var 시작좌표 = 0;

  $('.slide-box').eq(0).on('mousedown', function(e){
    시작좌표 = e.clientX;
  });

  $('.slide-box').eq(0).on('mousemove', function(e){
    console.log(e.clientX - 시작좌표)
    $('.slide-container').css('transform', `translateX( ${e.clientX - 시작좌표}px )`)
  });
</script>

예전에 translateX를 조절하면 박스가 왼쪽으로 오른쪽으로 이동했었습니다.

그래서 그거 줬습니다. margin-left 이런거 줘도 되긴 할듯요 

근데 약간 반응이 느린 이유는 예전에 .slide-container 박스에 transition : all 1s; 이런걸 추가해서 그런가봅니다.

transition어쩌구 붙어있던 css 코드를 삭제하면 잘됩니다. 

 

 

 

 

 

 

 

왜 마우스 클릭도 안했는데 박스가 움직임?

 

오늘도 주인님이 시키는대로 하는 컴퓨터는 전혀 죄가 없습니다.

"클릭하고나서만 박스 이동해달라"고 컴퓨터에게 명령을 주면 됩니다. 

 

 

 

설명하다
 
<script>
  var 시작좌표 = 0;

  $('.slide-box').eq(0).on('mousedown', function(e){
    시작좌표 = e.clientX;
  });

  $('.slide-box').eq(0).on('mousemove', function(e){
    if (마우스눌렀냐???) {
      $('.slide-container').css('transform', `translateX( ${e.clientX - 시작좌표}px )`)
    }
  });
</script>

if문 추가하면 되는거 아닙니까 

근데 마우스 눌렀는지 아닌지는 어떻게 판단하죠?

그건 다행히 mousedown 이벤트리스너가 있군요 그 안에서 판단하면 될 것 같습니다.

 

 

 

 

 

설명하다
 
<script>
  var 시작좌표 = 0;

  $('.slide-box').eq(0).on('mousedown', function(e){
    시작좌표 = e.clientX;
    var 눌렀냐 = true;
  });

  $('.slide-box').eq(0).on('mousemove', function(e){
    if (눌렀냐 === true) {
      $('.slide-container').css('transform', `translateX( ${e.clientX - 시작좌표}px )`)
    }
  });
</script>

1. 마우스 누르면 var 눌렀냐 변수를 true로 만들라고 코드짰습니다.

2. 그리고 if문에선 var 눌렀냐가 true일 때만 박스움직이라고 코드짰습니다.

근데 함수 안에 있던 변수는 함수 바깥으로 탈출 못한다고 하지 않았습니까 

그래서 제대로 동작안할듯요 실행해보면 var 눌렀냐라는 변수없다고 나올듯 

 

해결하고 싶으면 모든 곳에서 사용가능한 전역변수를 만들어 사용해야합니다.

 

 

설명하다
 
<script>
  let 시작좌표 = 0;
  let 눌렀냐 = false;

  $('.slide-box').eq(0).on('mousedown', function(e){
    시작좌표 = e.clientX;
    눌렀냐 = true;
  });

  $('.slide-box').eq(0).on('mousemove', function(e){
    if (눌렀냐 === true) {
      $('.slide-container').css('transform', `translateX( ${e.clientX - 시작좌표}px )`)
    }
  });
</script>

전역변수 만들었더니 변수사용가능합니다.

그리고 변수명 많아지면 중복생길까봐 기념으로 let 변수써봤습니다. 

 

기능2. 마우스 떼었을 때 이동거리가 100 이상이면 2번사진 보여주기

 

이거는 마우스를 떼면 실행할 기능이니까 mouseup 이벤트리스너안에 코드짜면 되겠군요 

 

설명하다
 
<script>
  (생략)

  $('.slide-box').eq(0).on('mouseup', function(e){
    눌렀냐 = false;

    if (이동거리 100이상) {
      2번사진보여주셈 
    } else {
      1번사진보여주셈
    }
  });
</script>

그래서 if 사용해서 코드짜봤습니다.

 

Q. 이동거리는 어떻게 구하죠? 

그건 저번시간에 e.clientX - 시작좌표 이렇게 구해봤습니다. 그거 넣으면 될듯요 

근데 안타깝게도 e.clientX - 시작좌표는 다른 함수안에 있어서 함부로 가져다쓰지 못합니다.

쓰고싶으면 전역변수 하나 만들면 되는 것임 

 

 

 

 

 

설명하다
 
<script>
  (생략)

  $('.slide-box').eq(0).on('mouseup', function(e){
    눌렀냐 = false;

    if (e.clientX - 시작좌표 < -100) {
      $('.slide-container').css('transform', 'translateX(-100vw)');
    } else {
      $('.slide-container').css('transform', 'translateX(0vw)');
    }
  });
</script>

근데 실은 전역변수없이 그냥 e.clientX - 시작좌표 써도 이동거리가 잘 나올듯요?

여기서 e.clientX 출력하면 '마우스 뗐을 때 좌표'가 나오니까요.

 

"2번사진 보여주세요~" 이거는 박스를 -100vw 만큼 움직이면 됩니다.

캐러셀 만들 때 했으니까 설명은 생략합니다. 

 

 

 

 

 

 

근데 마우스 떼면 왜 사진이 순간이동함 

 

마우스 떼면 2번사진으로 이동하라고 코드짰기 때문입니다.

서서히 이동하는 애니메이션 추가는 안했으니까요. 

애니메이션주고 싶으면 이동할 박스에 css transition 추가하면 됩니다.

 

근데 문제가 있는데

이전 강의에서 기능1 만들 때 불편해서 .slide-container 박스에 있던 transition을 제거했습니다.

왜냐면 누르고 사진을 스와이프할 때는 transition이 있으면 느리게 동작했으니까요.

 

- 그래서 평소엔 transition이 필요가 없는데 

- 사진에서 마우스를 떼면 transition이 필요합니다.

그럼 "마우스 떼면 잠깐 0.5초정도 transition 붙였다가 떼주세요" 

라고 코드짜면되지않을까요?

예전에 배운 타이머같은거 활용하면 가능합니다. transition 붙여놓고 0.5초 후에 떼라고 하면 됩니다. 

 

 

 

 

설명하다
 
<script>
  (생략)

  $('.slide-box').eq(0).on('mouseup', function(e){
    눌렀냐 = false;

    if (e.clientX - 시작좌표 < -100) {
      $('.slide-container').css('transition', 'all 0.5s').css('transform', 'translateX(-100vw)');
    } else {
      $('.slide-container').css('transition', 'all 0.5s').css('transform', 'translateX(0vw)');
    }
    setTimeout(()=>{
      $('.slide-container').css('transition', 'none')
    }, 500)
    
  });
</script>

1. 마우스 떼면 transition : all 0.5s 이거 부착하라고 코드짰습니다.

jQuery는 저렇게 점찍고 계속 추가할 수 있습니다. 쌩자바스크립트는 변경사항이2개면 2줄 작성하면 됩니다.

2. 그리고 setTimeout 이용해서 0.5초 후에 transition : none을 주라고 코드짰습니다. 

그럼 아까 한글로 설명했던거 구현 끝

 

 

 

 

 

 

 

모바일은 터치 이벤트리스너 달아야함 

 

사이트를 모바일기기로 테스트하고 싶으면 크롬개발자도구 좌상단 toggle device toolbar 버튼누르면 됩니다. 

근데 모바일기기로 테스트해보면 스와이프가 안됩니다.

왜냐면 마우스이벤트리스너를 달아놨기 때문입니다.

모바일은 터치이벤트리스너를 달아줘야 터치에 반응합니다.

 

 

touchstart (터치시작시 발동)

touchmove (터치중일 때 계속 발동)

touchend (터치종료시 발동)

이런 이벤트를 듣는 리스너를 부착하면 이제 터치스와이프 가능

 

 

설명하다
 
<script>
  $('.slide-box').eq(0).on('touchstart', function(){
    시작좌표 = e.touches[0].clientX;
    생략
  })

  $('.slide-box').eq(0).on('touchmove', function(){
    생략
  })

  $('.slide-box').eq(0).on('touchend', function(){
    생략
  })

</script>

기존 코드를 이렇게 바꾸면 됩니다.

그럼 모바일에서도 아까랑 똑같이 동작하는데 주의사항은 

e.clientX를 e.touches[0].clientX 이걸로 바꾸면 됩니다.

왜냐면 터치는 여러 손가락으로 할 수 있어서 그 중 몇번째 손가락인지 지정해줘야합니다. 

touchend 이벤트리스너에선 e.clientX 말고 e.changedTouches[0].clientX 쓰면 됩니다. 

 

 

Q. 어 그럼 PC환경에서는 안되는데요?

그럼 기존걸 touch로 바꾸는게 아니라 touch 이벤트리스너3개를 하단에 추가하면 됩니다. 

 

 

 

 

 

 

아 코드 너무 기네 

 

불만이 있으면 언제나 자바스크립트 만든 사람에게 따져야지 어쩔 수 없습니다. 

그래서 자바스크립트는 외부 라이브러리 의존도가 언제나 높은데 

Hammer.js 같은거 가져다쓰면 조금 쉽게 기능개발이 가능합니다. 

- 브라우저 호환성도 알아서 잡아주고

- 이벤트리스너 6개대신 1개만 써도 되고 

- 스와이프, pinch, rotate 등 여러 제스쳐를 감지하는 이벤트리스너 제공해서 편리하고

그렇기 때문에 심심하면 찾아봅시다. 

 

 

 

 

 

 

 

그래서 오늘 집에 가져갈 내용은 

 

다른 강의랑 책들 보면 맨날 느끼는 점인데 

"캐러셀에 스와이프 기능을 만들어볼까요? 우선 변수부터 5개 만들어봅시다~~" 그런 식으로 가르치는 경우가 많던데  

변수가 필요할지 처음부터 어떻게 알죠 

미리 답을 알고 있거나 천재면 가능할듯 

 

 

 

그래서 오늘 집에 가져갈 내용은 

"아 캐러셀 스와이프기능만들려면 변수2개, 이벤트리스너 3개부터 만들고 시작하면 되는구나" 가 아닙니다.

1. 유저의 터치를 여러방식으로 감지할 수 있구나~

2. 터치좌표, 터치이동거리도 출력해볼 수 있구나 

이것만 잘 알아가면 되겠습니다. 

그래야 나중에 캐러셀 스와이프말고 다른거 터치기능도 알아서 만들 수 있지 않겠습니까 

 

오늘도 코드만 따라쳤다면 지우고 1주 후에 다시 답보지말고 만들어봅시다.

이상한 변수 10개와 이벤트리스너부터 만들어야되는게 아니라 

- 구현하고 싶은 기능과 동작방식을 한글로 상세히 설명부터 하고

- 작고 쉬운 것 부터 개발해나가면 됩니다.