본문 바로가기

프로그래밍/JavaScript(JS)

자바스크립트(JavaScript)/웹(Web) - 이벤트

글에 오류가 있을 수 있으니 있다면 알려주시기 바랍니다.!

 

html 요소에 자바스크립트를 이용하여 이벤트를 처리하는 법을 간단히 알아보겠습니다.

 

이벤트는 특정 상황에대한 행동을 뜻합니다. 자바스크립트에서 특정 상황이 되었을 때 지정한 콜백 함수를 호출합니다.

 

이벤트 처리 방법

이벤트를 처리하는 방법은 여러개가 있습니다.

  • onclick 속성을 이용해 이벤트 처리
  • DOM 객체로 요소를 가져와 onclick 프로퍼티로 이벤트 처리
  • addEventListener() 메서드를 이용해 이벤트 처리
<button id="btn" onclick="show() ">클릭!</button>
<button id="btn2">클릭2!</button>
<button id="btn3">클릭3!</button>
<script>
  function show() {
    console.log("이벤트");
  }

  let btn2 = document.getElementById("btn2");
  btn2.onclick = show;

  let btn3 = document.getElementById("btn3");
  btn3.addEventListener("click", show);
</script>

html 요소에서 onclick 속성을 이용해서 이벤트를 처리하면 html와 자바스크립트가 섞여있어서 유지보수성이 떨어집니다. 또한 이벤트 처리를 위해 함수를 지정할 때 여러 개가 아닌 하나만 된다는 점입니다.

 

DOM 객체를 이용해 onclick에 이벤트 처리를 하는 것도 여러 개가 아닌 하나만 됩니다. 자바스크립트에서 이벤트를 처리하면 html과 분리가 되어있어서 보기가 편하고 유지보수가 좀 더 수월해집니다. 

 

따라서 이벤트를 여러 개를 설정할 수 있으며 html과 분리하여 사용할 수 있는 addEventLisener() 메서드를 이용하는 것이 좋습니다. 

 

addEventListener() 메서드 알아보기

이벤트를 추가하기 위해서는 요소를 가져와서 addEventListener() 메서드를 사용하면 됩니다.

let btn3 = document.getElementById("btn3");
btn3.addEventListener("click", show);

addEventListener() 메서드의 인수들은 다음과 같습니다.

  • type - 지정할 이벤트 유형입니다.
  • listener - 지정한 이벤트가 발생되면 호출되는 함수입니다.
  • useCapture - useCapture는 이벤트의 캡처와 버블링을 설정합니다. boolean 값으로 설정할 수 있으며 true인 경우 캡처 false인 경우 버블링일 때 리스너를 호출합니다. 기본값은 false입니다.
  • options - 리스너의 특성을 지정하는 옵션입니다.

버블링과 캡처링을 설정하여 이벤트가 전파되는 것을 정할 수 있습니다.

 

자세한 내용은 해당 링크를 참고하시기 바랍니다.

https://developer.mozilla.org/ko/docs/Web/API/EventTarget/addEventListener

 

EventTarget.addEventListener() - Web API | MDN

EventTarget의 addEventListener() 메서드는 지정한 이벤트가 대상에 전달될 때마다 호출할 함수를 설정합니다.

developer.mozilla.org

이벤트 삭제하기

addEventListener() 메서드로 설정한 이벤트 리스너는 removeEventListener() 메서드를 통해 삭제를 할 수 있습니다.

해당 메서드는 이벤트 리스너를 추가할 때 했던 인수들과 동일해야지만 이벤트 리스너를 제거할 수 있습니다.

let btn3 = document.getElementById("btn3");
btn3.addEventListener("click", function a() {
  console.log("이벤트 삭제할래요!");
  btn3.removeEventListener("click",a);
});

이렇게 하면 이벤트가 한 번만 실행이 됩니다.

 

removeEventListener() 메서드도 인수가 같습니다. 

https://developer.mozilla.org/ko/docs/Web/API/EventTarget/removeEventListener

 

EventTarget.removeEventListener() - Web API | MDN

EventTarget.removeEventListener() 메서드는 이전에EventTarget.addEventListener()로 EventTarget 에 등록했던 이벤트 리스너를 제거합니다. 이 이벤트 리스너는 이벤트 종류와 이벤트 리스너 함수 자체의 조합으

developer.mozilla.org

이벤트 객체

이벤트 객체는 발생한 이벤트의 대한 정보들이 있는 객체입니다. 만약 클릭 이벤트였다면 마우스에 대한 정보들이 들어있습니다. 

 

이벤트 객체는 이벤트 리스너에 지정한 함수에 하나의 인자 값을 만들어 주면 됩니다.

보통 e, event으로 인자값을 만들어줍니다. 아무 이름도 되지만 편하게 씁니다.

let btn = document.getElementById("button");
btn.addEventListener("click", function a(e) {
  console.log(e.target);
});

해당 코드를 확인하면 클릭된 요소가 나타납니다.

 

이벤트 객체 상황에 따라서 다른 프로퍼티가 있으니 링크를 참고하시기 바랍니다.

https://developer.mozilla.org/ko/docs/Web/API/Event

 

Event - Web API | MDN

Event 인터페이스는 DOM 내에 위치한 이벤트를 나타냅니다.

developer.mozilla.org

이벤트 기본 동작 중지

웹에서 기본적으로 지원하는 이벤트 행동을 막고 하고 싶은 코드를 실행하는 방법도 있습니다. 예를 들어 submit 할 때 기본 동작을 제한할 수 있습니다. 유효성 검사할 때 사용해볼 수 있겠습니다. 

 

사용법은 이벤트 객체를 가져와 preventDefault() 메서드를 호출해주면 끝입니다.

<form>
  <div>
    <label for="name">이름: </label>
    <input id="name" type="text">
  </div>
  <div>
    <input id="submit" type="submit">
  </div>
</form>

<script>
  let form = document.querySelector("form");
  let name = document.getElementById("name");
  form.onsubmit = function(e)
  {
    if(name.value == "") {
      e.preventDefault();
      console.log("submit 취소됨");
    }
  }
</script>

이벤트 전파

html 요소들의 이벤트 중에서 제일 중요한 내용입니다.

 

클릭 같은 행위는 화면을 클릭해야 합니다. html 요소가 여러 개 겹쳐있을 때도 있겠죠.

 

이때 겹쳐있는 부분을 클릭했을 때 어떤 것이 클릭이 되었는지 모르기 때문에 해당하는 이벤트가 등록되어 있는 것을 확인하고 모두 실행합니다. 

 

html 요소에서 이벤트가 발생되면 자식 요소와 부모 요소에 이벤트가 전파가 됩니다.

 

이벤트가 퍼지는 단계는 3가지 단계가 있습니다. 캡처링, 타겟, 버블링 단계입니다.

 

예전 브라우저는 캡처링과 버블링을 각각 사용했다고 합니다. 하지만 요즘 브라우저는 버블링을 사용한다고 하니 참고하시기 바랍니다. 만약 캡처링과 버블링을 모두 사용하는 브라우저라면 캡처링 후 버블링 단계가 진행됩니다.

 

캡처링 단계는 위에서 아래로 이벤트가 전파되어 실행됩니다. 만약 이벤트가 addEvnetListener() 메서드로 useCapture 인수가 true으로 추가된 이벤트가 있다면 해당 캡처링 단계에서 실행됩니다. 그 후 타겟 단계로 넘어갑니다.

 

타겟 단계에서는 실제적인 html 요소의 이벤트가 실행됩니다. 그 후 버블링 단계로 넘어갑니다.

 

버블링 단계 타겟단계에서 이벤트가 실행되고 다시 거슬러 올라가는 단계입니다. 타겟 단계의 html 요소의 부모로 거슬러 올라갑니다. 따라서 같은 이벤트 있다면 Window 객체까지 거슬러 올라가면서 이벤트가 실행됩니다.

 

간략하게 정리하면 클릭이 되는 순간 Window 객체에서부터 useCapture가 true 이벤트를 클릭한 html 요소까지 이벤트가 실행되고 그 후 클릭한 html의 요소의 이벤트가 실행되고 그 후 다시 Window 객체까지 같은 이벤트가 거슬러서 올라갑니다.

 

이벤트 전파 막기

버블링이 되면 원하는 방향으로 이벤트가 실행이 되지 않을 수 있습니다. 이런 문제를 해결할 수 있는 방법이 있습니다.

버블링 되는 것을 막아주는 stopPropagation() 메서드가 있습니다.

 

아래 코드가 있습니다.

<div id="a" style="width: 50px; height: 50px; background-color: black;">
  <div id="b" style="width: 50px; height: 50px; margin: 10px; background-color: aqua;">

  </div>
</div>

<script>
let a = document.getElementById("a");
let b = document.getElementById("b");

window.onclick = function () {
  console.log("윈도우");
}

a.addEventListener("click",function() {
  console.log("a 클릭");
});
b.addEventListener("click",function() {
  console.log("b 클릭");
});
</script>

// ->b 클릭
// ->a 클릭
// ->윈도우

b를 클릭하면 클릭하면 버블링 되면서 a 이벤트와 마지막으로 윈도우에 등록된 클릭 이벤트가 실행됩니다.

 

b 클릭 -> a 클릭 -> 윈도우 순으로 로그가 찍힙니다.

 

버블링 아래에서 위로 올라오게 되면서 b -> a -> 윈도우가 되는 겁니다.

 

여기서 b의 이벤트에서 이벤트 객체에 있는 stopPropagation() 메서드를 이용하면 버블링 되지 않습니다.

<div id="a" style="width: 50px; height: 50px; background-color: black;">
  <div id="b" style="width: 50px; height: 50px; margin: 10px; background-color: aqua;">

  </div>
</div>

<script>
let a = document.getElementById("a");
let b = document.getElementById("b");

window.onclick = function () {
  console.log("윈도우");
}

a.addEventListener("click",function(e) {
  console.log("a 클릭");
});
b.addEventListener("click",function(e) {
  e.stopPropagation();
  console.log("b 클릭");
});
</script>

// -> b 클릭

결과는 b 클릭만 로그에 찍히게 됩니다.

 

참고

모던 자바스크립트 입문(이소 히로시 지음, 서재원 옮김)

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events