Slider With Progress Bar

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

FE 기능구현 연습

목록 보기
26/33

HTML

    <div class="slider-wrap">
      <div class="slider">
        <div class="slider-inner">
          <div class="item">
            <h3>Item One</h3>
          </div>
          <div class="item">
            <h3>Item Two</h3>
          </div>
          <div class="item">
            <h3>Item Three</h3>
          </div>
          <div class="item">
            <h3>Item Four</h3>
          </div>
          <div class="item">
            <h3>Item Five</h3>
          </div>
          <div class="item">
            <h3>Item Six</h3>
          </div>
          <div class="item">
            <h3>Item Seven</h3>
          </div>
          <div class="item">
            <h3>Item Eight</h3>
          </div>
          <div class="item">
            <h3>Item Nine</h3>
          </div>
          <div class="item">
            <h3>Item Ten</h3>
          </div>
        </div>
      </div>
      <div class="progress-bar">
        <div class="prog-bar-inner"></div>
      </div>
    </div>

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

CSS

컨테이너보다 inner의 길이를 길게 잡는 게 포인트

.slider
overflow: scroll로 스크롤 기능 만들고,
스크롤바만 지우려면

크롬/사파리/오페라
elem.::-webkit-scrollbar { 
display: none; 
}
IE/파이어폭스
elem {
-ms-overflow-style: none;
  scrollbar-width: none;
}
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

h3 {
  color: #000000;
}

.slider-wrap {
  position: absolute;
  top: 10%;
  left: 5%;
  width: 90%;
  height: 300px;
  border: 1px solid black;
  cursor: grab;
}

.slider {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  overflow: scroll;
  -ms-overflow-style: none; /* IE and Edge */
  scrollbar-width: none; /* Firefox */
}

/* Chrome, Safari and Opera */
.slider::-webkit-scrollbar {
  display: none;
}

.slider-inner {
  position: absolute;
  display: flex;
  justify-content: space-around;
  top: 0;
  left: 0;
  height: 100%;
  width: 3000px;
}

.item {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 250px;
  height: 98%;
  top: 1%;
  border: 1px solid #000000;
  background-color: #d3d2d2;
}

.progress-bar {
  position: absolute;
  bottom: -20px;
  left: 0;
  width: 100%;
  height: 5px;
  border: 1px solid #000000;
  border-radius: 10px;
}

.prog-bar-inner {
  position: absolute;
  top: 0;
  left: 0;
  width: 0%;
  height: 100%;
  background-color: #383838;
}

JS

너비가 긴 내부 요소와 감싸고 있는 요소를 const로 선언한다.

parentElement : 노드의 부모 요소를 반환하는데, 부모가 없거나 부모가 DOM 요소가 아니라면 Null을 반환한다.

mousedown : 마우스클릭
mouseup : 마우스클릭떼기
mouseleave : slider에서 벗어나더라도 grab 유지하도록

mousemove
움직일 때 grab 상태이면 값 빼주기.
movementX => 마우스 움직임 양을 기록한다.

scrollLeft는 수평 스크롤값이다. 오른쪽으로 밀면 값이 증가함.

deltaY는 마우스 y축 스크롤양

scrollWidth : 보여지는 것과 상관없이 실제 콘텐츠 영역의 너비
clientWidth : 실제로 보여지고 있는 콘텐츠 영역의 너비

아래 코드에서
slider.parentElement.scrollWidth는 3000으로 고정
slider.parentElement.clientWidth는 801로 고정

scrollWidth와 clientWidth는 고정이므로
scrollLeft만 변하므로 이에 따라 프로그레스바 너비 결정됨.

scroll 이벤트는 최상위 부모에게만 적용하도록

scroll의 경우 event.preventDefault()로 막아도 기본 동작이 막아지지 않는다. event.preventDefault()가 동작하기 전에 scroll 이벤트가 발생하기 때문. 이때는 다른 이벤트에서 event.preventDefault()를 적용해야 한다. 예를 들어 아래 예제코드에서는 wheel에 적용했다.

const slider = document.querySelector(".slider-inner");
const progressBar = document.querySelector(".prog-bar-inner");

let sliderGrabbed = false;

slider.parentElement.addEventListener("scroll", (e) => {
  progressBar.style.width = `${getScrollPercentage()}%`;
});

slider.addEventListener("mousedown", (e) => {
  sliderGrabbed = true;
  slider.style.cursor = "grabbing";
});

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

slider.addEventListener("mouseleave", (e) => {
  sliderGrabbed = false;
  slider.style.cursor = "grab";
});

slider.addEventListener("mousemove", (e) => {
  if (sliderGrabbed) {
    slider.parentElement.scrollLeft -= e.movementX;
  }
});

slider.addEventListener("wheel", (e) => {
  e.preventDefault();
  slider.parentElement.scrollLeft += e.deltaY;
});

function getScrollPercentage() {
  return (
    (slider.parentElement.scrollLeft /
      (slider.parentElement.scrollWidth - slider.parentElement.clientWidth)) *
    100
  );
}

참고

JavaScript: Create A Device Friendly Product Slider With Progress Bar

profile
https://medium.com/@wooleejaan

0개의 댓글