Events

현성·2023년 12월 6일
0

기본 HTML

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script type="module" defer src="./main.js"></script>
  <style>
    .parent {
      width: 300px;
      height: 200px;
      padding: 20px;
      border: 10px solid;
      background-color: red;
      overflow: auto;
    }

    .child {
      width: 200px;
      height: 100px;
      border: 10px solid;
      background-color: orange;
      font-size: 40px;
    }
  </style>
</head>

<body>
  <div class="parent">
    <div class="child">
      <a href="javascript:void(0)">
        HYUNSUNG
      </a>
    </div>
  </div>
</body>

</html>

addEventListener()

  • 대상에 이벤트 청취(Listen)를 등록합니다.
  • 대상에 지정한 이벤트가 발생했을 때 지정한 함수(Handler)가 호출됩니다.
const parentEl = document.querySelector(".parent");
const childEl = document.querySelector(".child");

parentEl.addEventListener("click", () => {
  console.log("Parent!");
});

childEl.addEventListener("click", () => {
  console.log("Child!");
});

removeEventListener()

  • 대상에 등록했던 이벤트 청취(Listen)를 제거합니다.
  • 메모리 관리를 위해 등록한 이벤트를 제거하는 과정이 필요할 수 있습니다.
const parentEl = document.querySelector(".parent");
const childEl = document.querySelector(".child");

const handler = () => {
  console.log("Parent!");
};

parentEl.addEventListener("click", handler);
childEl.addEventListener("click", () => {
  parentEl.removeEventListener("click", handler);
});

이벤트 객체

  • 이벤트 객체는 대상에서 발생한 이벤트 정보를 담고 있습니다.
const parentEl = document.querySelector(".parent");

parentEl.addEventListener("click", (event) => {
  console.log(event.target, event.currentTarget);
});

parentEl.addEventListener("wheel", (event) => {
  console.log(event);
});

const inputEl = document.querySelector("input");

inputEl.addEventListener("keydown", (event) => {
  console.log(event.key);
});

기본 동작 방지

  • event.preventDefault()는 이벤트는 작동하지만 브라우저의 기본 동작을 막아줍니다.
// 마우스 휠의 스크롤 동작 방지
const parentEl = document.querySelector(".parent");
parentEl.addEventListener("wheel", (event) => {
  event.preventDefault();
  console.log("Wheel!");
});

// <a> 태그에서 페이지 이동 방지
const anchorEl = document.querySelector("a");
anchorEl.addEventListener("click", (event) => {
  event.preventDefault();
  console.log("Click!");
});

이벤트 전파(버블) 정지

  • 이벤트가 상위 요소로 전파되는 것을 방지합니다.
  • addEventListener메소드의 세번째 인수로 { capture: true }를 추가해주면 해당 이벤트가 먼저 동작하도록 합니다.
// 마우스 휠의 스크롤 동작 방지
const parentEl = document.querySelector(".parent");
const childEl = document.querySelector(".child");
const anchorEl = document.querySelector("a");

window.addEventListener("click", (event) => {
  console.log("Window!");
});

document.body.addEventListener("click", (event) => {
  console.log("Body!");
});

parentEl.addEventListener("click", (event) => {
  console.log("Parent!");
  event.stopPropagation(); // 버블링 정지!
});

childEl.addEventListener("click", (event) => {
  console.log("Child!");
});

anchorEl.addEventListener("click", (event) => {
  console.log("Anchor!");
});

이벤트에 capture: true 인수를 추가하였다면 이벤트를 삭제할 때도 인수로 capture: true을 추가해줘야 합니다.

const parentEl = document.querySelector(".parent");

const handler = () => {
  console.log("Parent!");
};

parentEl.addEventListener("click", handler, { capture: true });
parentEl.removeEventListener("click", handler, { capture: true });

이벤트 옵션

// 핸들러 한 번만 실행

const parentEl = document.querySelector(".parent");

parentEl.addEventListener(
  "click",
  (event) => {
    console.log("Parent");
  },
  {
    once: true,
  }
);
// 기본 동작과 핸들러 실행 분리

const parentEl = document.querySelector(".parent");

parentEl.addEventListener(
  "wheel",
  () => {
    for (let i = 0; i < 1000; i += 1) {
      console.log(i);
    }
  },
  {
    passive: true,
  }
);

이벤트 위임(Delegation)

  • 비슷한 패턴의 여러 요소에서 이벤트를 핸들링해야 하는 경우, 단일 조상 요소에서 제어하는 이벤트 위임 패턴을 사용할 수 있습니다.

기본 HTML

<body>
  <div class="parent">
    <div class="child">1</div>
    <div class="child">2</div>
    <div class="child">3</div>
    <div class="child">4</div>
  </div>
</body>
const parentEl = document.querySelector(".parent");
const childEls = document.querySelectorAll(".child");

// 모든 대상 요소에 이벤트 등록 !
// childEls.forEach((el) => {
//   el.addEventListener("click", (event) => {
//     console.log(event.target.textContent);
//   });
// });

// 조상 요소에 이벤트 위임 !
parentEl.addEventListener("click", (event) => {
  const childEl = event.target.closest(".child");
  if (childEl) {
    console.log(childEl.textContent);
  }
});

Mouse & Pointer Events

  • click : 클릭했을 때
  • dblclick : 더블 클릭했을 때
  • mousedown : 버튼을 누를 때
  • mouseup : 버튼을 땔 때
  • mouseenter : 포인터가 요소 위로 들어갈 때
  • mouseleave : 포인터가 요소 밖으로 나올 때
  • mousemove : 포인터가 움직일 때
  • contextmenu : 우클릭했을 때 (우클릭 시 브라우저 기본동작을 event.preventDefault()로 막을 수 있습니다.
  • wheel : 휠 버튼이 회전할 때

Keyboard Event

  • keydown : 키를 누를 때

  • keyup : 키를 땔 때

  • event.isComposing은 CJK 문자를 처리하는 과정인지를 불린데이터로 가지고 있는 속성입니다.

const inputEl = document.querySelector("input");

inputEl.addEventListener("keydown", (event) => {
  if (event.key === "Enter" && !event.isComposing) {
    console.log(event.target.value);
  }
});

Focus & Form Events

  • focus : 요소가 포커스를 얻었을 때
  • blur : 요소가 포커스를 잃었을 때
  • input : 값이 변경되었을 때
  • change : 상태가 변경되었을 때
  • submit : 제출 버튼을 선택했을 때
  • reset : 리셋 버튼을 선택했을 때

기본 HTML

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script type="module" defer src="./main.js"></script>
  <style>
    form {
      padding: 10px;
      border: 4px solid transparent;
      display: flex;
      flex-wrap: wrap;
      gap: 6px;
    }

    form.active {
      border-color: orange;
    }
  </style>
</head>

<body>
  <form>
    <input type="text" placeholder="ID">
    <input type="password" placeholder="PW">
    <button type="submit">제출</button>
    <button type="reset">초기화</button>
  </form>
</body>

</html>
const formEl = document.querySelector("form");
const inputEls = document.querySelectorAll("input");

inputEls.forEach((el) => {
  el.addEventListener("focus", () => {
    formEl.classList.add("active");
  });
  el.addEventListener("blur", () => {
    formEl.classList.remove("active");
  });
  el.addEventListener("change", (event) => {
    console.log(event.target.value);
  });
});

formEl.addEventListener("submit", (event) => {
  event.preventDefault();
  const data = {
    id: event.target[0].value,
    pw: event.target[1].value,
  };
  console.log("제출!", data);

  formEl.addEventListener("reset", (event) => {
    console.log("리셋!");
  });
});

커스텀 이벤트와 디스패치

기본 HTML

<body>
  <div class="parent">
    <div class="child">1</div>
    <div class="child">2</div>
  </div>
</body>
const child1 = document.querySelector(".child:nth-child(1)");
const child2 = document.querySelector(".child:nth-child(2)");

child1.addEventListener("click", (event) => {
  // 강제로 이벤트 발생 !
  child2.dispatchEvent(new Event("click"));
  child2.dispatchEvent(new Event("wheel"));
  child2.dispatchEvent(new Event("keydown"));
});
child2.addEventListener("click", (event) => {
  console.log("Child2 Click!");
});
child2.addEventListener("wheel", (event) => {
  console.log("Child2 Wheel!");
});
child2.addEventListener("keydown", (event) => {
  console.log("Child2 Keydown!");
});

const child1 = document.querySelector(".child:nth-child(1)");
const child2 = document.querySelector(".child:nth-child(2)");

child1.addEventListener("hello-world", (event) => {
  console.log("커스텀 이벤트 발생 !");
  console.log(event.detail);
});

child2.addEventListener("click", () => {
  child1.dispatchEvent(
    new CustomEvent("hello-world", {
      detail: 123,
    })
  );
});
// 커스텀 이벤트 발생 !
// 123
profile
👈🏻 매일 꾸준히 성장하는 개발자 !

0개의 댓글