이벤트 기초

김수정·2020년 6월 2일
1

브라우저 Javascript

목록 보기
5/9

이벤트란?

이벤트는 갑자기 일상과 다른 무언가가 발생하는 거죠. 마찬가지로 프로그래밍에서도 이벤트는 갑자기 발생한 무언가입니다.
이벤트는 DOM에만 한정되는 것은 아닙니다.
자주 사용되는 이벤트의 종류에는 마우스 이벤트, 폼요소 이벤트, 키보드 이벤트, 문서 이벤트, css이벤트... 등이 있습니다.

이벤트 핸들러

이벤트가 발생했을 때 실행되는 함수입니다. 핸들러를 할당하는 방법은 여러가지가 있습니다.

html 속성으로 지정

on<event> 속성으로 할당합니다.

<input value="클릭해 주세요." onclick="alert('클릭!')" type="button">

주의할 점

  • html 속성은 문자열로 넣게 되어있으므로 따옴표에 신경을 써야 합니다. 문자열의 시작을 onClick의 끝으로 오역할 수 있습니다.
  • 코드가 긴 경우에는 좋은 방법이 아닙니다. 가독성도 많이 떨어지고, 이 방법을 써야한다면 차라리 함수를 따로 만들어서 연결하세요.
  • html 속성은 대소문자를 구분하지 않기 때문에 onClick으로 써도 동작하지만 대개 소문자로만 적습니다.
  • 복수의 이벤트 핸들러를 등록할 수 없습니다.
  • 핸들러 내부에 쓰인 this는 핸들러가 할당된 요소입니다.
  • 브라우저가 속성값을 읽고 이 값을 함수 본문으로 하는 핸들러 함수를 만들기 때문에 on<event>() 형태로 작성해야 합니다.

Dom프로퍼티로 지정

DOM 프로퍼티 on<event>로 할당합니다.

<input id="elem" type="button" value="클릭해 주세요.">
<script>
  elem.onclick = function() {
    alert('감사합니다.');
  };
  
  elem.onclick = null // 핸들러 제거
</script>

주의할 점

  • 복수의 이벤트 핸들러를 등록할 수 없습니다.
  • 핸들러 내부에 쓰인 this는 핸들러가 할당된 요소입니다.
  • 이벤트 핸들러는 등록하는 것이지 호출하는 것이 아닙니다. 함수명() 형태가 아니라 함수명입니다.
  • 대소문자를 구분하므로 정확한형태로 이벤트를 지정해야합니다.
  • setAttribute로 핸들러를 할당하지 않습니다. 이 메소드는 속성을 문자열로 저장하기 때문에 함수로 등록되지 않습니다.

addEventListener로 지정

element.addEventListener(event, handler, [options])

  • event: event name
  • handler: event handler
  • options: 아래 프로퍼티를 갖는 객체
    - once: true면 이벤트가 트리거될 때 리스너가 자동으로 삭제됩니다.
    - capture: 캡쳐링 여부
    - passive: true면 리스너에서 지정한 함수가 preventDefault()를 호출하지 않습니다.

element.removeEventListener(event, handler, [options])
핸들러 삭제는 핸들러 등록했던 함수를 그대로 전달해주어야 합니다. 그렇게 하기 위해서 핸들러 함수를 따로 만들어야 합니다. 익명함수로 할당해버리면 삭제할 수 없습니다.

주의할 점

  • addEventListener를 여러 개 호출하면 이벤트를 여러 개 등록할 수 있습니다.
  • addEventListener로 등록해야만 동작하는 이벤트가 있습니다.
  • 객체로 핸들러를 지정할 수 있습니다. 이 경우에는 객체 안에 handleEvent(event)라는 메소드가 있어야 합니다.
<button id="elem">클릭해 주세요.</button>

<script>
  class Menu {
    handleEvent(event) {
      switch(event.type) {
        case 'mousedown':
          elem.innerHTML = "마우스 버튼을 눌렀습니다.";
          break;
        case 'mouseup':
          elem.innerHTML += " 그리고 버튼을 뗐습니다.";
          break;
      }
    }
  }

  let menu = new Menu();
  elem.addEventListener('mousedown', menu);
  elem.addEventListener('mouseup', menu);

이벤트 객체

이벤트에 관한 상세한 정보를 넣은 자료. 핸들러에 인수 형태로 전달됩니다.

<input type="button" value="클릭해 주세요." id="elem">

<script>
  elem.onclick = function(event) {
    // 이벤트 타입과 요소, 클릭 이벤트가 발생한 좌표를 보여줌
    alert(event.type + " 이벤트가 " + event.currentTarget + "에서 발생했습니다.");
    alert("이벤트가 발생한 곳의 좌표는 " + event.clientX + ":" + event.clientY +"입니다.");
  };
</script>

event.type
이벤트 유형

event.currentTarget
이벤트를 처리하는 요소.

event.clientX / event.clientY
마우스 관련 이벤트에서 커서의 상대 좌표.(브라우저 화면 기준 좌표)

버블링

이벤트 버블링(bubbling)이란 한 요소에서 이벤트가 발생하면 root document를 만날 때까지 연결된 이벤트를 연쇄적으로 확장 실행시키는 것입니다.
거의 모든 이벤트는 버블링이 됩니다.

버블링과 연관된 이벤트 객체

event.target 실제 이벤트가 시작된 '타깃'입니다. 버블링이 진행되어도 변하지 않습니다.
event.currentTarget(this) '현재'요소. 실행중인 핸들러가 할당된 요소를 참조합니다.

버블링 중단

event.stopPropagation() - 부모요소로 번지는 버블링을 막아줌. 다른 핸들러의 동작은 막지 못함.
event.stopImmediatePropagation() - 해당 요소에 할당된 모든 핸들러의 동작/버블링을 막아줌.

캡쳐링

버블링의 반대 의미로 이벤트가 발생한 타깃까지 root부터 이벤트를 발생시키면서 내려오는 것입니다.
addEventListener의 options에서 제어 가능합니다. 이 옵션 제어는 핸들러를 제거하는 removeEventListener에서도 동일하게 적용해줘야 삭제가 됩니다.

event.eventPhase – 현재 이벤트 흐름 단계(캡처링=1, 타깃=2, 버블링=3)

이벤트 위임

  1. 컨테이너에 하나의 핸들러를 할당합니다.
  2. 핸들러의 event.target을 사용해 이벤트가 발생한 요소가 어디인지 알아냅니다.
  3. 원하는 요소에서 이벤트가 발생했다고 확인되면 이벤트를 핸들링합니다.
let selectedTd;

table.onclick = function(event) {
  let td = event.target.closest('td'); // (1) 가장 가까운 조상으로 td가 있는가

  if (!td) return; // (2) 없으면 동작하지 않음

  if (!table.contains(td)) return; // (3) 중첩 테이블일 수 있으므로 테이블 바로 아래있는 td인지 알아봄

  highlight(td); // (4) 기능 동작
};

function highlight(td) {
  if (selectedTd) { // 이미 강조되어있는 칸이 있다면 원상태로 바꿔줌
    selectedTd.classList.remove('highlight');
  }
  selectedTd = td;
  selectedTd.classList.add('highlight'); // 새로운 td를 강조 함
}

브라우저 기본동작 제어

브라우저의 기본 동작 막기

  1. event.preventDefault()
  2. on<event>로 할당한 이벤트라면 return false로 기본 동작을 막을 수 있습니다.

addEventListener의 'passive'옵션

addEVentListener의 passive옵션을 true로 주면 preverntDefault()를 호출하지 않겠으니 그거 찾지말고 더 유려하고 빠르게 동작하라는 뜻입니다.

event.defaultPrevented

기본 동작을 막으면 true, 아니면 false가 할당되어 있습니다.

<p>문서 레벨 컨텍스트 메뉴(event.defaultPrevented를 확인함)</p>
<button id="elem">버튼 레벨 컨텍스트 메뉴</button>

<script>
  elem.oncontextmenu = function(event) {
    event.preventDefault();
    alert("버튼 컨텍스트 메뉴");
  };

  document.oncontextmenu = function(event) {
    if (event.defaultPrevented) return;

    event.preventDefault();
    alert("문서 컨텍스트 메뉴");
  };
</script>

custom event

event생성자

let event = new Event(type[, options]);
  • type - event type
  • options: 아무값도 지정하지 않으면 {bubbles: false, cancelable: false}
    - bubbles: bubbling true/false
    - cancelable: 브라우저 기본 동작 실행여부 true/false

커스텀 이벤트 생성자

detail프로퍼티는 커스텀 이벤트 관련 정보를 명시하고, 정보를 이벤트에 전달할 수 있습니다.

<h1 id="elem">이보라님, 환영합니다!</h1>

<script>
  // 추가 정보는 이벤트와 함께 핸들러에 전달됩니다.
  elem.addEventListener("hello", function(event) {
    alert(event.detail.name);
  });

  elem.dispatchEvent(new CustomEvent("hello", {
    detail: { name: "보라" }
  }));
</script>

dispatchEvent

이벤트를 실행시킵니다.

event.isTrusted

이벤트가 스크립트를 통해 생성한 이벤트인지 진짜 사용자가 만든 이벤트인지 알려줌.
true - 사용자가 만든 이벤트
false - 스크립트를 통해 만들어진 이벤트

*주의사항
on<Event>는 DOM 프로퍼티 적용이 안됨.

이벤트 안 이벤트

이벤트는 큐로 처리되므로 먼저 실행된 이벤트가 끝나야 다음 이벤트가 실행됩니다. 그런데 이벤트 안에 이벤트가 있다면 진행되던 이벤트를 멈추고 중첩된 이벤트가 먼저 실행됩니다.

profile
정리하는 개발자

0개의 댓글