이벤트와 이벤트 핸들러

Seunghyo Ku·2021년 1월 19일
0

JavaScript

목록 보기
1/3
post-thumbnail

이벤트는 웹 브라우저에서 DOM 요소와 사용자가 상호작용하는 것을 의미합니다.
예컨대, 사용자가 버튼을 클릭하거나 입력창에 정보를 입력하거나 하는 행위들은 모두 이벤트로 볼 수 있습니다.

Event Driven Program

이벤트 주도형 프로그램(Event Driven Program)은 컴퓨터 프로그램 중에서 특히 이벤트에 반응하여 동작을 변경하는 방식입니다. 이벤트가 발생할 때까지 기다렸다가, 사용자가 특정 이벤트를 발생시켰을 때, 미리 저장해둔 동작을 실행합니다.

이벤트 처리기

이벤트 처리기에는 어떤 것들이 있을까요?

클릭 이벤트에 관한 동작을 관리하는 onclick이 그 중 하나입니다. 각 주요 이벤트 처리기들은 다음과 같습니다.

이벤트 처리기종류
onclick마우스 클릭 시
ondbclick마우스 더블클릭 시
onmousedown마우스 버튼 누를 시
onmouseup마우스 버튼에서 손 뗄 시
onmouseout마우스 포인터가 요소를 벗어날 시
onmousemove마우스 포인터가 요소 위에서 움직일 시
onmouseover마우스 포인터가 요소 위에 올라왔을 시
onkeydown키보드 누를 시
onkeypress키보드를 누르고 손가락을 뗄 시
onkeyup키보드 키에서 손가락을 뗄 시
onchangeinput 요소 값이 바뀔 시(변경된 이후, 포커스를 잃을 때)
oninputinput 요소 값이 바뀔 시(바뀐 직후)
onblurinput 요소에서 focus를 잃을 시
onfocusinput 요소에서 focus가 주어질 시 (커서가 들어올 때)
onsubmit폼 제출 버튼을 누를 시
onload해당 페이지가 처음 읽힐 시(브라우저에서 문서를 읽을 때)
onunload해당 페이지를 나갈 시(브라우저에서 문서를 닫을 때)
onabort페이지나 이미지 읽어오기가 중단됐을 시
onerror페이지나 이미지를 읽어오는 중 오류가 발생할 시

위의 이벤트 처리기에 JavaScript로 작성된 함수를 넣어 원하는 동작을 처리하게 됩니다.

웹 브라우저가 HTML을 읽을 때 문서를 차례대로 읽는데, script 요소를 발견하면 실행시킨 이후, 뒤의 HTML을 읽어나갑니다. 동기적으로 동작하기 때문입니다.

이벤트처리기 추가 및 제거

  • 추가:
    target.addEventListener(type, listener, useCapture)
    useCapture은 true/false 중 하나입니다. (true: 캡처링 단계| false: 버블링 단계)

  • 제거:
    아밴트 처리기는 기본적으로 null이 담겨있기 때문에 제거하고자 할 때는 해당 처리기에 null 값을 대입하면 됩니다.

이벤트의 각 단계

이벤트에는 3가지 단계가 존재합니다.

  1. 캡처링 단계(capturing)
  2. 타깃 단계(target)
  3. 버블링 단계(bubbling)

1. 캡처링 단계:
캡처링은 Window 객체에서 시작해 DOM tree를 따라 target까지 전파됩니다.
캡처링 단계를 이용하는 경우는 흔치 않습니다. 그래도 혹시나 캡처링 단계에서 동작하는 이벤트를 추가하고 싶을 경우에는 아래와 같이 코드를 작성하면 됩니다.

target.addEventListener(type, listener, true) 혹은 target.addEventListener(type, listener, { captrue: true })

2. 타깃 단계:
이벤트가 실제 타깃 요소에 전달되는 단계입니다.
이벤트 흐름 단계 중 하나이지만, 캡처링과 버블링 단계의 핸들러는 타깃 단계에서 trigger 되기 때문에 별도로 처리되지 않습니다.

3. 버블링 단계:
이벤트가 상위 요소로 전파되는 단계입니다.
한 요소에 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고, 부모 요소의 핸들러가 연달아 동작하며 최상단의 요소(조상)을 만날 때까지 과정이 반복되면서 핸들러가 동작하게 됩니다.

즉, 이 동작은 document 객체를 만날 때까지 상위 요소의 이벤트 핸들러가 동작하게 됩니다. 이것이 거품이 몽글몽글 올라가는 것과 같아 bubbling이란 이름이 붙었다고 합니다.

캡처링과는 달리 false 값을 eventListener의 마지막 인자로 넣어주면 버블링 단계에서 동작하는 이벤트를 만들 수 있습니다.

target.addEventListener(type, listener, false) 혹은 target.addEventListener(type, listener, { captrue: false })

  • 다만, focusblur는 그 요소에만 필요한 이벤트이므로 이벤트 버블링이 발생하지 않는다고 합니다.
  • 이벤트 처리기와 리스너가 같은 요소, 같은 이벤트, 같은 단계에 반응하게끔 되어 있다면 이벤트 처리기가 먼저 실행되며 이벤트 리스너가 등록된 순서대로 동작하게 됩니다.
  • 같은 요소, 같은 이벤트에 대하여 각각 캡처링/버블링 단계에 모두 동작하도록 이벤트 리스너를 등록할 수 있습니다.

이벤트의 전파

자식 요소에서 발생하는 이벤트가 부모 요소에도 전파되기 때문에, 의도하지 않은 일을 막고자 이벤트 전파를 취소하거나 멈출 수도 있습니다.

  • event.stopPropagation(): 이벤트가 다음 요소로 전달되는 것을 막는다.
  • event.stopImmediatePropagation(): 그 다음 요소로의 전파가 일시적으로 멈추고, 그 객체의 그 이벤트에 등록한 다른 이벤트 리스너도 일시적으로 동작을 멈춥니다.
  • event.preventDefault(): 기본적으로 구현된 동작을 취소할 수 있습니다. (submit 버튼을 누르면 발생하는 새로고침 등을 막을 수 있습니다.)

event.target과 this

  • event.target: 실제 이벤트가 시작된 요소 (=target)
    - 버블링이 진행되더라도 변하지 않습니다.
  • this: 현재 실행중인 핸들러가 할당된 요소(= 함수를 호출할 때 그 함수가 속해 있던 객체의 참조)

예를 들어, onclick 이벤트가 가장 상위에 있는 form에만 존재한다고 할 때, 위의 이미지에서 P를 클릭하면 this와 target은 아래와 같습니다.

  • this: form (onclick 처리 존재함)
  • target: p (이벤트가 실제로 발생함)

this 조종하기

1. bind
bind()메서드는 객체에 함수를 bind합니다.
this가 특정 객체를 가리키게 하고 싶을 때 사용합니다.

function cola() {
  console.log("콜라는 역시 " + this.name);
}

const cocaCola = { name: "코카콜라" };
const bestCola = cola.bind(cocaCola);
// 콜라는 역시 코카콜라
  1. 익명 함수
    익명 함수 안에서 메서드를 호출하면, 그 메서드의 this가 메서드를 참조하는 객체를 기킵니다.

  2. addEventListener의 두 번째 인수로 객체를 넘기는 방법
    함수 대신 객체를 인자로 넘길 수 있습니다.

리액트에서의 이벤트

아래는 velog를 만드신 벨로퍼트 님이 작성한 책을 보고 정리해보았습니다.

  1. 카멜 표기법으로 작성한다.
  2. 함수 형태의 값을 전달한다.
  3. DOM 요소에만 이벤트를 설정할 수 있다.

메서드 이름 짓기

다양하게 지을 수 있지만, 시청한 강의와 책에서는 handleFunction() 으로 명칭하여 가독성을 높였습니다.

input 여러 개 다루기

input이 여러 개일 때, 여러 이벤트 처리 함수를 만들 수도 있지만 event 객체를 호라용할 수도 있습니다. event.target.name 값을 활용하면 됩니다.

객체 안에서 key를 []로 감싸면 그 안에 넣은 레퍼런스가 가리키는 실제 값이 key 값으로 사용됩니다. 이것을 이용해서 코드를 작성하면 다음과 같습니다.

handleChange = (e) => {
  this.setState({
    [e.target.name]: e.target.value;
  })
}

enter 작성시 event 발생시키기

handleClick = (e) => {
  alert(this.state.username + ': ' + this.state.message)
  this.setState({
   username: '',
    message: ''
  });
}

handleKeyPress = (e) => {
  if (e.key === 'enter') {
    this.handleClick();
  }
}

[출처]
모던자바스크립트 입문(이소 히로시 저)
모던 자바스크립트 버블링과 캡처링(https://ko.javascript.info/bubbling-and-capturing)
리액트를 다루는 기술(김민준 저)

profile
꼬꼬마 개발자 구승효입니다!

0개의 댓글