[코딩애플] JavaScript 강의 정리 (Level2 11강 ~ 12강)

이언덕·2024년 4월 25일

코딩애플

목록 보기
13/37
post-thumbnail

11강 / 이벤트 버블링과 이벤트관련 함수들

모달창 배경을 누르면 닫히는 기능을 추가하기

앞선 강의에서 모달창을 하나 제작해서 띄워봤다.

이제 위 모달창에서 검은 배경을 누르면 모달창이 닫히는 기능을 추가해볼 것이다.

현재 모달창이 열리는 것과 닫히는 메커니즘은 아래와 같다.

const modalBtn = document.querySelector(".modal-btn");
const modal = document.querySelector(".black-bg");
const modalCloseBtn = document.querySelector("#close");

modalBtn.addEventListener("click", showModal);
modalCloseBtn.addEventListener("click", closeModal);

function showModal() {
  modal.classList.add("show");
}

function closeModal() {
  modal.classList.remove("show");
}

모달창 버튼을 누르게 되면 .black-bg.show가 추가로 붙는다.
그리고 닫기 버튼을 누르게 되면 .black-bg의 추가로 붙은 .show가 삭제가 되어 모달창이 사라지는 메커니즘이다.

현재 내가 원하는 그림은 닫기버튼이 아니라 검은배경을 눌렀을 때 모달창이 닫히는 것이기 때문에 이벤트리스너를 살짝 바꾸어주면 될 것 같다.

const modalBtn = document.querySelector(".modal-btn");
const modal = document.querySelector(".black-bg");

modalBtn.addEventListener("click", showModal);
modal.addEventListener("click", closeModal);

function showModal() {
  modal.classList.add("show");
}

function closeModal() {
  modal.classList.remove("show");
}

위 코드로 바꾸게 된다면 검은색 배경을 눌렀을 때 closeModal 함수가 실행되면서 .black-bg의 추가로 붙은 .show가 삭제된다.


근데 이상한 점이 하나 있다.
검은배경 뿐만 아니라 흰배경, input, 글자 등 모달창 내부의 어떤걸 눌러도 다 닫히는 것을 볼수 있다.

이 부분을 해결하기 위해 이벤트 버블링 이란 것에 대해 먼저 배워보자.



이벤트 버블링

어떤 HTML 태그이벤트가 발생하면 그의 모든 상위요소까지 이벤트가 실행되는 현상을 이벤트 버블링이라고 한다.
click이라는 이벤트로 예를 들어보면,
HTML 태그에 클릭이 발생하면 그의 모든 상위요소까지 자동으로 클릭된다는 말이다.

더 자세하게 알아보기 위해 한 사이트를 참고하였다. 아래 사이트를 자세히 읽어보고 정확하게 이해한 뒤 넘어가자!
이벤트 버블링 & 캡쳐링

<div>
  <div>
    <p>안녕</p>
  </div>
</div>

▲위의 코드에서 p태그 안녕이라는 글자를 클릭하면 브라우저는 사용자가 클릭을 총 3번 했다고 인지한다.
p랑 그 위의 div랑 그 위의 div랑 이렇게
이게 이벤트 버블링인데 브라우저는 원래 그렇게 동작하도록 되어있다.
이 사실을 모르고 코드짜다보면 가끔 이상한 현상이 발생할 수도 있다!

이제 검은 배경을 누르면 모달창이 닫히는 기능 코드를 다시 살펴보면
왜 흰배경 눌러도 모달창이 닫히냐면

<div class="black-bg"> (← 이거 누르면 모달창 닫으라고 코드짰음)
  <div class="white-bg">
    모달창 내용
  </div>
</div>

유저가 <div class="white-bg"> 이거 클릭해도
이벤트 버블링 때문에 <div class="black-bg"> 이것도 클릭한 것이다.
그래서 거기 붙어있던 이벤트리스너가 동작해서 모달창을 닫아주는 것이다.
이 문제를 해결할 때 자주 사용하는 이벤트관련 함수/메소드들을 살펴보자.



이벤트리스너 안에서 쓰는 이벤트 함수들

document.querySelector('.black-bg').addEventListener('click', function(e){
  e.target;
  e.currentTarget;
  e.preventDefault();
  e.stopPropagation();
})

이벤트리스너의 콜백함수에 파라미터 아무거나 추가하면 이벤트관련 유용한 함수들을 사용가능하다.
파라미터 이름은 아무렇게나 작명하면 됩니다. 보통 대충 e라고 한다.
e.target은 실제 클릭한 요소 알려준다. (이벤트 발생한 곳)
e.currentTarget은 지금 이벤트리스너가 달린 곳을 알려준다. (참고로 this라고 써도 똑같음)
e.preventDefault() 실행하면 이벤트 기본 동작을 막아준다. (이 부분을 Level1 10강 form부분에서 사용해보았다.)
e.stopPropagation() 실행하면 내 상위요소로의 이벤트 버블링을 중단해준다.
몇개만 뽑아봤는데 필요할 때 찾아서 사용하면 될 것 같다.

여기서 중요한건 e.target인데
e.target을 한번 출력해보자

function closeModal(e) {
  console.log(e.target);
  modal.classList.remove("show");
}

닫기기능에서 e.target을 한번 출력해보면

내가 누른 요소를 콘솔에 출력하는 것을 볼 수 있다.
이벤트 버블링이 일어난다고 해도 사용자가 실제로 클릭한 그 요소는 저 문법으로 찾아낼 수 있다는걸 기억해둬야한다.



그럼 모달창 닫기 버그를 해결해봅시다

이제 코드를 수정해보자
한글로 먼저 코드를 짜놓은 뒤.
자바스크립트로 바꾸어보자

function closeModal(e) {
  지금 실제로 클릭한게 검은 배경이라면? 모달창을 닫아주세요
}

위 처럼 짤 수 있겠다. if문을 사용해서 코드를 짜보자

function closeModal(e) {
  if ((e.target == modal)) {
    modal.classList.remove("show");
  }
}


결과를 보면 검은배경만 눌렀을 때 모달창이 닫히는 것을 볼 수 있다.



index 전체코드

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
      crossorigin="anonymous" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" type="text/css" href="./index.css" />
    <title>Coding Apple JavaScript</title>
  </head>
  <body>
    <!-- <div id="alert-box">
      알림창임
      <button id="alert-close-btn">❌</button>
    </div>
    <button id="alert-notification-btn">알림창 여는 버튼</button>
    <button id="alert-id-btn">
      로그인
    </button>
    <button
      id="alert-password-btn"
     >
      비밀번호
    </button> -->

    <!-- <nav class="navbar navbar-light bg-light">
      <div class="container-fluid">
        <span class="navbar-brand">Navbar</span>
        <button class="navbar-toggler" type="button">
          <span class="navbar-toggler-icon"></span>
        </button>
      </div>
    </nav>
    <ul class="list-group">
      <li class="list-group-item">An item</li>
      <li class="list-group-item">A second item</li>
      <li class="list-group-item">A third item</li>
      <li class="list-group-item">A fourth item</li>
      <li class="list-group-item">And a fifth one</li>
    </ul> -->

    <button class="modal-btn">모달창 버튼</button>
    <div class="black-bg">
      <div class="white-bg">
        <h4>로그인하세요</h4>
        <form action="success.html">
          <div class="my-3">
            <input type="text" class="form-control" id="modal-id" />
          </div>
          <div class="my-3">
            <input type="password" class="form-control" id="modal-password" />
          </div>
          <button type="submit" class="btn btn-primary">전송</button>
          <button type="button" class="btn btn-danger" id="close">닫기</button>
        </form>
      </div>
    </div>

    <!-- <span class="badge bg-dark">Dark 🔄</span> -->

    <!-- <div style="overflow: hidden">
      <div class="slide-container">
        <div class="slide-box">
          <img src="./assets/car1.png" />
        </div>
        <div class="slide-box">
          <img src="./assets/car2.png" />
        </div>
        <div class="slide-box">
          <img src="./assets/car3.png" />
        </div>
      </div>
    </div>
    <button class="btn1">1</button>
    <button class="btn2">2</button>
    <button class="btn3">3</button>
    <button class="prev"><</button>
    <button class="next">></button>

    <div class="lorem" style="width: 200px; height: 100px; overflow-y: scroll">
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quae voluptas
      voluptatum minus praesentium fugit debitis at, laborum ipsa itaque placeat
      sit, excepturi eius. Nostrum perspiciatis, eligendi quae consectetur
      praesentium exercitationem.
    </div> -->

    <script src="./index.js"></script>
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
      crossorigin="anonymous"></script>
  </body>
</html>

index.css

body {
  height: 3000px;
}

#alert-box {
  background-color: skyblue;
  padding: 20px;
  color: white;
  border-radius: 5px;
  display: none;
}
.list-group {
  display: none;
}
.black-bg {
  visibility: hidden;
  opacity: 0;
  width: 100%;
  height: 100%;
  position: fixed;
  background: rgba(0, 0, 0, 0.5);
  z-index: 5;
  padding: 30px;
  transition: all 1s;
}
.white-bg {
  background: white;
  border-radius: 5px;
  padding: 30px;
}

.show {
  visibility: visible;
  opacity: 1;
}

.slide-container {
  width: 300vw;
  transition: all 1s;
}
.slide-box {
  width: 100vw;
  float: left;
}
.slide-box img {
  width: 100%;
}

.navbar {
  position: fixed;
  width: 100%;
  z-index: 5;
}
.navbar-brand {
  font-size: 30px;
  transition: all 1s;
}

index.js

// const notification = document.querySelector("#alert-box");
// const notificationBtn = document.querySelector("#alert-notification-btn");
// const closeBtn = document.querySelector("#alert-close-btn");
// const idBtn = document.querySelector("#alert-id-btn");
// const passwordBtn = document.querySelector("#alert-password-btn");
// const navbarBtn = document.querySelector(".navbar-toggler");
// const subMenu = document.querySelector(".list-group");
const modalBtn = document.querySelector(".modal-btn");
const modal = document.querySelector(".black-bg");
const modalCloseBtn = document.querySelector("#close");
const formIdInput = document.querySelector("#modal-id");
const formPassWordInput = document.querySelector("#modal-password");
const submitBtn = document.querySelector(".btn-primary");
// const darkmodeBtn = document.querySelector(".badge");
// const slideContainer = document.querySelector(".slide-container");
// const carouselBtn1 = document.querySelector(".btn1");
// const carouselBtn2 = document.querySelector(".btn2");
// const carouselBtn3 = document.querySelector(".btn3");
// const carouselNext = document.querySelector(".next");
// const carouselPrev = document.querySelector(".prev");
// const scrollNavFont = document.querySelector(".navbar-brand");
// const scrollAlert = document.querySelector(".lorem");

// notificationBtn.addEventListener("click", showNotification);
// closeBtn.addEventListener("click", closeNotification);
// navbarBtn.addEventListener("click", showSubmenu);
// navbarBtn.addEventListener("click", closeSubmenu);
modalBtn.addEventListener("click", showModal);
modal.addEventListener("click", closeModal);
submitBtn.addEventListener("click", checkInput);
// darkmodeBtn.addEventListener("click", changeMode);
// carouselBtn1.addEventListener("click", handleCarousel1);
// carouselBtn2.addEventListener("click", handleCarousel2);
// carouselBtn3.addEventListener("click", handleCarousel3);
// carouselNext.addEventListener("click", handleCarouselNext);
// carouselPrev.addEventListener("click", handleCarouselPrev);
// window.addEventListener("scroll", handleScroll1);
// scrollAlert.addEventListener("scroll", handleScroll2);

// function showNotification() {
//   notification.style.display = "block";
// }

// function closeNotification() {
//   notification.style.display = "none";
// }

// function handleIdBox(text) {
//   notification.style.display = "block";
//   notification.innerText = text;
// }

// function handlePassWordBox(text) {
//   notification.style.display = "block";
//   notification.innerText = text;
// }

// function toggleSubmenu() {
//   subMenu.classList.toggle("show");
// }

function showModal() {
  modal.classList.add("show");
}

function closeModal(e) {
  if (e.target == modal) {
    modal.classList.remove("show");
  }
}

function checkInput(event) {
  if (formIdInput.value == "") {
    event.preventDefault();
    alert("아이디를 입력하세요");
  } else if (/\S+@\S+\.\S+/.test(formIdInput.value) == false) {
    event.preventDefault();
    alert("이메일 형식이 아닙니다");
  } else if (formPassWordInput.value == "") {
    event.preventDefault();
    alert("비밀번호를 입력하세요");
  } else if (formPassWordInput.value.length <= 6) {
    event.preventDefault();
    alert("비밀번호 7자리 이상 입력하세요");
  } else if (/[A-Z]/.test(formPassWordInput.value) == false) {
    event.preventDefault();
    alert("비밀번호에 영어 대문자를 넣으세요");
  }
}

// let darkCount = 1;
// function changeMode() {
//   darkCount += 1;
//   if (darkCount % 2 == 0) {
//     darkmodeBtn.classList.remove("bg-dark");
//     darkmodeBtn.classList.add("bg-light");
//     darkmodeBtn.style.color = "black";
//   } else {
//     darkmodeBtn.classList.remove("bg-light");
//     darkmodeBtn.classList.add("bg-dark");
//     darkmodeBtn.style.color = "white";
//   }
// }

//캐러쉘 1번
// let nowPhoto = 0;
// function handleCarousel1() {
//   nowPhoto = 0;
//   slideContainer.style.transform = `translateX(-${nowPhoto}00vw)`;
// }

//캐러쉘 2번
// function handleCarousel2() {
//   nowPhoto = 1;
//   slideContainer.style.transform = `translateX(-${nowPhoto}00vw)`;
// }

//캐러쉘 3번
// function handleCarousel3() {
//   nowPhoto = 2;
//   slideContainer.style.transform = `translateX(-${nowPhoto}00vw)`;
// }

//캐러쉘 Next버튼
// function handleCarouselNext() {
//   if (nowPhoto == 0) {
//     nowPhoto += 1;
//     slideContainer.style.transform = `translateX(-${nowPhoto}00vw)`;
//   } else if (nowPhoto == 1) {
//     nowPhoto += 1;
//     slideContainer.style.transform = `translateX(-${nowPhoto}00vw)`;
//   }
// }

//캐러쉘 Prev버튼
// function handleCarouselPrev() {
//   if (nowPhoto == 2) {
//     nowPhoto -= 1;
//     slideContainer.style.transform = `translateX(-${nowPhoto}00vw)`;
//   } else if (nowPhoto == 1) {
//     nowPhoto -= 1;
//     slideContainer.style.transform = `translateX(-${nowPhoto}00vw)`;
//   }
// }

// function handleScroll1() {
//   if (window.scrollY >= 100) {
//     scrollNavFont.style.fontSize = "20px";
//   } else if (window.scrollY <= 100) {
//     scrollNavFont.style.fontSize = "30px";
//   }
// }

// function handleScroll2() {
//   const scroll = scrollAlert.scrollTop;
//   const height = scrollAlert.scrollHeight;
//   const clientHeight = scrollAlert.clientHeight;
//   if (scroll + clientHeight == height) {
//     alert("끝입니다");
//   }
// }



12강 / 이벤트 버블링 응용과 dataset

이벤트버블링을 알고계시면 이벤트리스너를 줄여가며 개발할 수도 있다.
필수나 그런건 아니고 알면 언젠가 도움되는 내용이기 때문에
전에 만들었던 탭기능을 다시 만들어보자.

전에 만들었던 탭기능 함수로 축약해보기

detail파일로 가서 작업을 해야한다.

함수쓰면 긴 코드를 짧은 단어하나로 축약할 수 있다고 했다.
그래서 탭만들 때 썼던 4줄의 코드를 함수로 축약해볼 것이다.
함수로 넣으면

    1. 재사용이 편리하고
    1. 나중에 남이 읽었을 때도 뭔가 이해가 쉬울 수 있다.
for (let i = 0; i < buttons.length; i++) {
  buttons[i].addEventListener("click", function () {
    handleTap(i);
  });
}

function handleTap(i) {
  buttons.forEach((button) => {
    button.classList.remove("orange");
  });

  contents.forEach((content) => {
    content.classList.remove("show");
  });

  buttons[i].classList.add("orange");
  contents[i].classList.add("show");
}

위와 같이 파라미터를 이용하여 바꿀 수 있다.

Q. 왜 파리미터를 사용하나요?
A. 함수로 코드를 싸맬 때 안에 변수가 들어있으면 변수를 전부 파라미터로 바꾸는게 좋다.

그래야 잘 동작한다. 그래서 i 부분을 전부 파라미터로 바꿔주었다.
이제 함수 사용할 때
탭열기(0) 이러면 0번 탭이 열림
탭열기(1) 이러면 1번 탭이 열림
탭열기(2) 이러면 2번 탭이 열림



이벤트버블링을 알면 이벤트리스너 줄일 수 있음

이벤트버블링을 통해 탭 기능을 완성시켜보자.
버튼 3개의 부모인 <ul class="list"> 여기에 이벤트리스너 1개만 있어도 탭기능만들 수 있을 것 같다.
버튼 뭘 누르든 간에 <ul class="list">에 붙은 이벤트리스너도 동작하기 때문이다.
(왜냐면 이벤트버블링이 항상 일어나기 때문!)

const tabList = document.querySelector(".list");

tabList.addEventListener("click", function(){
  지금 누른게 버튼 0이면 탭열기(0) 실행
  지금 누른게 버튼 1이면 탭열기(1) 실행
  지금 누른게 버튼 2이면 탭열기(2) 실행
})

Q. 왜 굳이 이벤트리스너 줄여서 코드 짜나요?

  • 버튼이 몇십개 있다면 이렇게 짜는게 덜 복잡하고
  • 이벤트리스너를 줄이면 램용량을 절약할 수 있다. (성능개선의 일환이다.)

위 한글코드를 완성시켜보자

const tabList = document.querySelector(".list");

tabList.addEventListener("click", function (e) {
  if (e.target == buttons[0]) {
    handleTap(0);
  }
  if (e.target == buttons[1]) {
    handleTap(1);
  }
  if (e.target == buttons[2]) {
    handleTap(2);
  }
});

function handleTap(i) {
  buttons.forEach((button) => {
    button.classList.remove("orange");
  });

  contents.forEach((content) => {
    content.classList.remove("show");
  });

  buttons[i].classList.add("orange");
  contents[i].classList.add("show");
}

이렇게 for문을 사용하지 않아도 탭기능 잘되는 것을 볼 수 있다.
근데 이러나 저러나 코드 양은 똑같다.
dataset 문법을 알면 위 코드를 조금 더 짧게 바꿀 수도 있다.



dataset 문법 (잡기술)

<div data-데이터이름=""></div>

html 안에 유저 몰래 정보를 숨겨놓을 수 있다.
데이터이름 아무렇게나 작명하고 값도 넣으면 된다.


document.querySelector().dataset.데이터이름;

이러면 html 요소에 숨겨놨던 데이터가 이 자리에 남는다.
출력해보면 아까 숨겨놓은 값이 남는 것을 볼 수 있다.

htmlproducts버튼에 data의 이름은 id 값은 0을 숨겨놓았다.

<li class="tab-button" data-id="0">Products</li>
console.log(buttons[0].dataset.id);

실제로 콘솔에 출력해보면 0이 나오는 것을 알 수 있다.


이제 코드를 한번 수정해보자.

<li class="tab-button" data-id="0">Products</li>
<li class="tab-button orange" data-id="1">Information</li>
<li class="tab-button" data-id="2">Shipping</li>

▲ 우선 탭의 버튼들에 이렇게 데이터를 숨겨보자.

그리고 아까 코드를 다시 살펴보면 if문이 3개였다.
버튼0 누르면 탭열기(0) 실행해주세요~
버튼1 누르면 탭열기(1) 실행해주세요~
버튼2 누르면 탭열기(2) 실행해주세요~
위 코드를

아래 코드 처럼 바꾸면

tabList.addEventListener("click", function(){
  탭열기(지금누른버튼에 숨어있던 data-id)
});

▲ 근데 이렇게 코드짜면 굳이 if문이 필요없이 한 줄로 해결이 가능할 것 같다.


const tabList = document.querySelector(".list");

tabList.addEventListener("click",function(e){
  handleTap(e.target.dataset.id)
});

function handleTap(i) {
  buttons.forEach((button) => {
    button.classList.remove("orange");
  });

  contents.forEach((content) => {
    content.classList.remove("show");
  });

  buttons[i].classList.add("orange");
  contents[i].classList.add("show");
}

▲ 지금누른 버튼을 찾고 싶으면 e.target이고
거기 숨어있는 data-id 꺼내고 싶으면 .dataset.id 붙이면 된다.
그래서 위처럼 코드짜도 탭기능 완성이다.
이전 코드가 좋으면 그거 쓰면 되고 취향것 쓰면 될 것 같다.
(dataset 문법이 인터넷익스플로러 11+ 에서 동작하는 것을 미리 알고 있어야한다!)



detail 전체코드

datail.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
      crossorigin="anonymous" />
    <link rel="stylesheet" type="text/css" href="./detail.css" />
    <title>코딩애플 Vanila JS Level2</title>
  </head>
  <body>
    <div class="container mt-5">
      <ul class="list">
        <li class="tab-button" data-id="0">Products</li>
        <li class="tab-button orange" data-id="1">Information</li>
        <li class="tab-button" data-id="2">Shipping</li>
      </ul>
      <div class="tab-content">
        <p>상품설명입니다. Product</p>
      </div>
      <div class="tab-content show">
        <p>스펙설명입니다. Information</p>
      </div>
      <div class="tab-content">
        <p>배송정보입니다. Shipping</p>
      </div>
    </div>
  </body>
  <script src="./detail.js"></script>
</html>

datail.css

ul.list {
  list-style-type: none;
  margin: 0;
  padding: 0;
  border-bottom: 1px solid #ccc;
}
ul.list::after {
  content: "";
  display: block;
  clear: both;
}
.tab-button {
  display: block;
  padding: 10px 20px 10px 20px;
  float: left;
  margin-right: -1px;
  margin-bottom: -1px;
  color: grey;
  text-decoration: none;
  cursor: pointer;
}
.orange {
  border-top: 2px solid orange;
  border-right: 1px solid #ccc;
  border-bottom: 1px solid white;
  border-left: 1px solid #ccc;
  color: black;
  margin-top: -2px;
}
.tab-content {
  display: none;
  padding: 10px;
}
.show {
  display: block;
}

datail.js

const buttons = document.querySelectorAll(".tab-button");
const productsButton = buttons[0];
const informationButton = buttons[1];
const shippingButton = buttons[2];

const contents = document.querySelectorAll(".tab-content");
const productsContent = contents[0];
const informationContent = contents[1];
const shippingContent = contents[2];

const tabList = document.querySelector(".list");

/* 상품설명 클릭시 오렌지색줄이 생기고 상품설명이 설명으로 나옴 */
// function productsHandle() {
//   informationButton.classList.remove("orange");
//   shippingButton.classList.remove("orange");
//   productsButton.classList.add("orange");
//   informationContent.classList.remove("show");
//   shippingContent.classList.remove("show");
//   productsContent.classList.add("show");

// buttons.forEach((button) => {
//   button.classList.remove("orange");
// });
// contents.forEach((content) => {
//   content.classList.remove("show");
// });
// productsButton.classList.add("orange");
// productsContent.classList.add("show");
// }

/* 스펙설명 클릭시 오렌지색줄이 생기고 스펙설명이 설명으로 나옴 */
// function informationHandle() {
//   productsButton.classList.remove("orange");
//   shippingButton.classList.remove("orange");
//   informationButton.classList.add("orange");
//   productsContent.classList.remove("show");
//   shippingContent.classList.remove("show");
//   informationContent.classList.add("show");

// buttons.forEach((button) => {
//   button.classList.remove("orange");
// });
// contents.forEach((content) => {
//   content.classList.remove("show");
// });
// informationButton.classList.add("orange");
// informationContent.classList.add("show");
// }

/* 배송정보 클릭시 오렌지색줄이 생기고 배송정보이 설명으로 나옴 */
// function shippingHandle() {
//   productsButton.classList.remove("orange");
//   informationButton.classList.remove("orange");
//   shippingButton.classList.add("orange");
//   productsContent.classList.remove("show");
//   informationContent.classList.remove("show");
//   shippingContent.classList.add("show");

// buttons.forEach((button) => {
//   button.classList.remove("orange");
// });
// contents.forEach((content) => {
//   content.classList.remove("show");
// });
// shippingButton.classList.add("orange");
// shippingContent.classList.add("show");
// }

/* 위 3개의 기능을 for문으로 합치기 */
// for (let i = 0; i < buttons.length; i++) {
//   buttons[i].addEventListener("click", function () {
//     handleTap(i);
//   });
// }

tabList.addEventListener("click", function (e) {
  handleTap(e.target.dataset.id);
});

function handleTap(i) {
  buttons.forEach((button) => {
    button.classList.remove("orange");
  });

  contents.forEach((content) => {
    content.classList.remove("show");
  });

  buttons[i].classList.add("orange");
  contents[i].classList.add("show");
}

// productsButton.addEventListener("click", productsHandle);
// informationButton.addEventListener("click", informationHandle);
// shippingButton.addEventListener("click", shippingHandle);

0개의 댓글