본문 바로가기
개발/소소한 실습

vanila JS로 캐러셀 만들기

by 안뇽! 2022. 1. 30.
반응형

참고문서 : 

https://velog.io/@grinding_hannah/JavaScript-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A1%9C-%EC%BA%90%EB%9F%AC%EC%85%80Carousel-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0

 

깃허브 : 

https://github.com/ryu9663/css-practice

 

위의 참고문서를 기본 템플릿으로 해서 만들었다.

가운데 오는 요소는 배경이 하늘색으로 바뀌도록 추가하였다.

 

vanila JS로 만들다보니 그동안 소홀히 했던 DOM 메서드를 다시 복습할 수 있었다.


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" />
    <title>CSS 연습</title>
    <link rel="stylesheet" href="carousel.css" />
  </head>
  <body>
    <div class="window">
        <ul class="container">
          
          <li class="cell">5</li>
          <li class="cell">1</li>
          <li class="cell">2</l>
          <li class="cell">3</li>
          <!-- 하나를 주석처리하여 Cell개수가 홀,짝일때를 실험할 수 있다. -->
          <li class="cell">4</li>
        </ul>
      </div>
      <div class="button-container">
        <button class="prev">previous</button>
        <button class="next">next</button>
      </div>
      <script src = "button.js"></script>
  </body>
</html>

CSS

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

body {
  width: 2000px;
  height: 500px;
  display: absolute;
}

h1 {
  text-align: center;
  font-size: 50px;
  margin-top: 50px;
  color: #555;
}

.window {
  overflow: hidden;

  position: relative;
  top: 20%;
  left: 20%;
  transform: translateY(-50%);
  transform: translateX(-50%);
  border: 4px solid red;
  height: 130px;
  width: 300px;
}

.container {
  position: absolute;
  height: 120px;
  width: 630px;
  border: 4px solid green;
  left: -150px;
}

.cell {
  color: red;
  font-size: 30px;
  text-decoration: none;
  list-style: none;
  text-align: center;
  width: 100px;
  height: 100px;
  border: 4px solid #555;
  border-radius: 10px;
  background-color: pink;
  display: inline-block;
  margin: 10px 10px;
  padding-top: 30px;
}

button {
  font-size: 30px;
  height: 50px;
  width: 200px;
  background-color: #f6e58d;
  border: 4px solid #555;
  border-radius: 10px;
  margin-left: 130px;
  margin-top: 50px;
  cursor: pointer;
}

button:hover {
  background-color: #e3b854;
}

.button-container {
  position: relative;
  top: 25%;
  left: 0%;
  /* transform: translateY(-50%); */
  /* transform: translateX(-50%); */
}

JS

const container = document.querySelector(".container");
const prevBtn = document.querySelector(".prev");
const nextBtn = document.querySelector(".next");
//container.children은 유사배열이라 Array.from으로 배열화 한다. 밑에서 forEach메서드 사용하기 위함
const containerList = Array.from(container.children);
const carouselLength = container.children.length;
let centerCell =
  carouselLength % 2 !== 0 ? container.children[parseInt(carouselLength / 2)] : container.children[carouselLength / 2];

(function addEvent() {
  prevBtn.addEventListener("click", translateContainer.bind(this, 1));
  nextBtn.addEventListener("click", translateContainer.bind(this, -1));
})();

function translateContainer(direction) {
  const selectedBtn = direction === 1 ? "prev" : "next";
  container.style.transitionDuration = "500ms";
//이 줄만 주석 풀어주세요, 티스토리 에디터 문제때문에 부득이하게 주석처리함  container.style.transform = `translateX(${direction * (100 / carouselLength)}%)`;
  //ontransitioned event 는 CSS transition이 완려되었을때 실행된다.
  container.ontransitionend = () => reorganizeEl(selectedBtn);
  centerCell = getCenterCell(selectedBtn);
}

function reorganizeEl(selectedBtn) {
  container.removeAttribute("style");
  selectedBtn === "prev"
    ? //parentNode.insertBefore(newNode, referenceNode);
      //referenceNode앞에 newNode를 삽입한다.
      //만약 이미 존재하는 노드를 참조하면 이동시킨다.(추가하기 전에 삭제할 필요가 없다.)
      container.insertBefore(container.lastElementChild, container.firstElementChild)
    : //appendChild : 파라미터(노드)를 부모 노드의 자식 노드 리스트 중 마지막 자식으로 붙인다.
      //이미 문서에 존재한다면, 새로운 위치로 이동시킨다.(노드를 다른 곳으로 붙이기 전에 삭제할 필요가 없다.->한 노드가 두 지점에 동시에 존재할 수 없다.)
      //첫번째 노드를 마지막으로 옮긴다.
      container.appendChild(container.firstElementChild);
}

function getCenterCell(selectedBtn) {
  if (selectedBtn === "next") {
    //next버튼
    console.log(selectedBtn);
    centerCell = container.children[parseInt(carouselLength / 2) + 1];
  } else {
    //prev버튼
    console.log(container.children[0]);
    centerCell = carouselLength % 2 !== 0 ? container.children[1] : container.children[carouselLength / 2 - 1];
  }

  //centerCell은 하늘색으로,
  centerCell.style.background = "skyblue";

  //나머지 Cell은 분홍색으로
  containerList.forEach((el) => {
    if (el.textContent !== centerCell.textContent) {
      el.style.background = "pink";
    }
  });
  return centerCell;
}

 

반응형