draggable slider

woolee의 기록보관소·2022년 11월 15일
0

FE 기능구현 연습

목록 보기
25/33

HTML

<!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" />
    <link rel="stylesheet" href="style.css" />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
      integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    />
    <title>Draggable Slider</title>
  </head>
  <body>
    <div class="slider">
      <div class="slider-inner">
        <div class="slide-img">
          <i class="fas fa-futbol"></i>
        </div>
        <div class="slide-img">
          <i class="fas fa-football-ball"></i>
        </div>
        <div class="slide-img">
          <i class="fas fa-golf-ball"></i>
        </div>
        <div class="slide-img">
          <i class="fas fa-biking"></i>
        </div>
        <div class="slide-img">
          <i class="fas fa-basketball-ball"></i>
        </div>
        <div class="slide-img">
          <i class="fas fa-hockey-puck"></i>
        </div>
        <div class="slide-img">
          <i class="fas fa-swimmer"></i>
        </div>
      </div>
    </div>

    <script src="app.js"></script>
  </body>
</html>

CSS

.slider
컨테이너를 80%로 잡아 놓고,
overflow:hidden;으로 넘쳐 흐르는 건 안 보이게
.slider-inner
내부 너비는 200%로 잡아서 넘쳐 흐르도록

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

i {
  color: rgb(255, 255, 255);
  font-size: 3rem;
  pointer-events: auto;
  cursor: pointer;
}

i:hover {
  color: rgb(167, 11, 245);
}

.slider {
  position: absolute;
  left: 10%;
  top: 30%;
  width: 80%;
  height: 200px;
  overflow: hidden;
}

.slider-inner {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 200%;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 5px;
  pointer-events: none;
}

.slide-img {
  height: 100%;
  background-color: black;
  text-align: center;
  padding: 3rem;
}

JS

slider.addEventListener("mousedown", (e)=> {})
elem.onmousedown 요소 위에서 마우스 왼쪽 버튼 누를 때 발생

slider 위에서 마우스 왼쪽 버튼 누르면
presed = true;
마우스 커서 grabbing으로 바꿔주기

offsetX,Y는 이벤트 대상 객체에서의 상대적 마우스 좌표 반환
=> slider 위에서 클릭하면,
왼쪽 끝이 0, 오른쪽 끝이 제일 큰 값(slider 너비)을 반환함.

elem.offsetLeft : 상대적으로 가장 가까이 위치한 부모 요소(offsetParent)를 기준으로 지정 요소(elem) 좌측 상단 모서리 기준으로 상대 위치를 반환함.
=> slider 위에서 마우스 클릭한 채로 왼쪽으로 넘기면 음수값 반환. (slider-inner 너비를 더 길게 잡아놨으므로)

mouseenter, mouseup
slider에 진입하거나 클릭 떼면 커서 모양 grab으로 되도록

그리고 mouseup 되는 순간 pressed=false;로 바꿔주기

slider.addEventListener("mousemove", (e) => {})
마우스 클릭하고 있지 않으면 return해버리고

변수 X에 e.offsetX; 넣고
innerSlider.left 변경해서 내부에 있는 요소들을 왼쪽으로 이동하는 인터랙션 구현하기

그리고 그냥 냅두면 요소가 완전히 컨테이너를 벗어날 수 있음.
그래서 경계선을 판단하는 checkboundary() 함수 만들기

내부 이미지들이 끌려다닐 수 있으므로
e.preventDefault() 잡아주기

checkboundary()

if => 오른쪽으로 넘기다가 0보다 커지면 그냥 left 값 0px로 고정하기

else if => 왼쪽으로 넘기다가 다 넘겼으면 경계선에 값 고정하기

let slider = document.querySelector(".slider");
let innerSlider = document.querySelector(".slider-inner");

let pressed = false;
let startx;
let x;

slider.addEventListener("mousedown", (e) => {
  pressed = true;
  startx = e.offsetX - innerSlider.offsetLeft;
  slider.style.cursor = "grabbing";
});

slider.addEventListener("mouseenter", () => {
  slider.style.cursor = "grab";
});

// slider.addEventListener("mouseleave", () => {
//   slider.style.cursor = "default";
// });

slider.addEventListener("mouseup", () => {
  slider.style.cursor = "grab";
});

window.addEventListener("mouseup", () => {
  pressed = false;
});

slider.addEventListener("mousemove", (e) => {
  if (!pressed) return;
  e.preventDefault();

  x = e.offsetX;

  innerSlider.style.left = `${x - startx}px`;

  checkboundary();
});

function checkboundary() {
  let outer = slider.getBoundingClientRect();
  let inner = innerSlider.getBoundingClientRect();

  if (parseInt(innerSlider.style.left) > 0) {
    innerSlider.style.left = "0px";
  } else if (inner.right < outer.right) {
    innerSlider.style.left = `-${inner.width - outer.width}px`;
  }
}

참고

Vanilla JavaScript: Create A Draggable Slider

profile
https://medium.com/@wooleejaan

0개의 댓글