🍀 Event

event의 사전적인 의미는 사건 이란 의미가 있다. 필요한 물품을 샀을 때 통장에서 돈이 빠져나가는 사건이 일어난다…🥲

돈이 빠져나가서 통장에 잔고가 얼마 없다면 어떻게 할까?

이 때 내가 할 수 있는 행동(처리)는 아래와 같은 옵션들이 있을 것이다.

event occur 돈이 없어지면
option1 아낀다
option2 일을 해서 번다
option3 뻐긴다
option4 사려고 한 목록 중 몇 개를 없앤다

optionN

이렇게 보면 사건과 처리로 생각할 수 있다.

사건: 돈이 빠져나감
처리: 돈이 생길 때까지 뻐김…

웹에서도 event란 같은 의미이다. 좀 더 구체적으로 말하자면 웹에서의 이벤트는 사용자가 웹 브라우저에서 발생시키는 사건을 뜻한다.

아래는 사용자가 웹에서 이벤트를 발생시키는 예시들이다.

  • 브라우저에서 마우스 움직임
  • 브라우저에서 마우스로 클릭할 때
  • 브라우저 창 사이즈를 줄이거나 늘릴 때

위의 예시들이 발생했을 때 내가 실행시키고 싶은 로직을 구현하여 처리하면 되는 것이다. 그리고 위의 event들은 사실상 언제 발생할 지 모른다. 따라서 웹에서는 event가 발생했을 때 처리해줄 함수(callback) 를 브라우저에게 위임한다. 이것을 용어표현하면 아래와 같다.

  • 이벤트 핸들러(event handler): 이벤트가 발생했을 때 호출되는 함수
  • 이벤트 핸들러 등록: event handler를 브라우저에게 위임하는 행위

이렇게 사용자가 이벤트를 발생시켰을 때 브라우저가 처리하게 되면 사용자와 애플리케이션은 상호작용할 수 있게 되며 상호작용을 할 수 있게 이어주는 통로를 event handler가 담당한다고 생각할 수 있을 것 같다.

실생활에서 사건(event)는 무수히 많지만 웹에서 발생하는 event는 대략 200개 정도라고 한다.

그렇다면, 웹에서 발생할 수 있는 event 종류는 무엇이 있을까?

본 블로그에서는 크게 자주 쓰이는 document/window, mouse, keyboard, form event에 관해서 다룬다.

🍀 Event Type

1. Document/Window Event

eventevent가 발생하는 순간
loadbrowser가 모든 리소스(image, script …)들이 로드되었을 때 발생하며 , script를 head안에 defer 속성 없이 추가하면 페이지가 load될 때 실행시키는 event로서 적절하다.
unload웹 페이지가 unload 되었을 때 발생하는 이벤트. ex) 주로 새로운 페이지를 요청한 경우
error자바스크립트의 오류 또는 자원이 존재하지 않는 경우 발생하는 이벤트
resize브라우저 창의 크기를 줄이거나 늘릴 때 발생하는 이벤트.
scroll브라우저 내에서 스크롤할 때와 스크롤바를 가진 특정 요소(textarea)들 내에서 스크롤할 때 발생하는 이벤트
readystatechangeHTML 문서가 로딩 또는 파싱 되는 과정의 상태를 나타내는 이벤트이다. document.readyState(value → ‘loading’, ‘interactive’, ‘complete’)의 value가 변경될 때 발생하는 이벤트이다.
DOMContentLoadedHTML 문서를 로딩하고 파싱이 끝날 때 즉, DOM 생성이 완료되었을 때(DOM Tree & CSSOM Tree가 완료되었을 때) 발생하는 이벤트로 render tree를 생성할 수 있는 상태다. 하지만, 이미지, 하위 프레임의 로딩은 기다리지 않는다.

문서의 readyState는 다음의 값중의 하나를 갖는다.

loading : 웹 문서가 로딩중인 상태이다.
interactive : 웹 문서의 로딩이 완료되고 해석이 되는 시점이며 하위 리소스(image, stylesheet, iframe 등)가 아직 로딩중인 상태이다.
complete : 웹 문서의 DOM 완성과 모든 하위 리소스들의 로드가 완료된 상태이며 load 이벤트가 발생되기 직전의 시점으로 바로 직전에 DOMContentLoaded event가 실행된다.

여기서는 나에게 생소한 readystatechange와 DOMContentLoaded event를 다루기로 했다. 아래 예시를 만드는 과정에서 browser rendering process(critical rendering path)의 개념이 너무 부족하여 공부하느라 시간이 어마무시하게 걸렸다. ㅜㅜ 😭😭 지금 내 수준에서 엄청 필요한 개념은 아닌 것 같지만 이해를 못 하니 오기가 발생했다..ㅋㅋ

readystatechange와 DOMContentLoaded를 이해하기 위해 아래와 같은 예시를 만들어봤다.

<!-- index.html -->
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script src="./src/index.js" defer></script>
    <title>Document</title>
  </head>
  <body></body>
</html>
// index.js
window.addEventListener("load", (event) => {
  console.log("window onload");
});

document.addEventListener("readystatechange", (event) => {
  console.log("readystatechange", document.readyState);
});

document.addEventListener("DOMContentLoaded", (event) => {
  console.log("DOMContentLoaded");
});

먼저 위의 코드의 결과를 확인하고 이해하기 이전에 browser의 rendering과정을 이해할 필요가 있다. 아래 그림을 참조하자. 👇

그리고 HTML의 head안에 script tag가 defer나 async 속성을 주지 않은 채로존재한다고 가정하면, 아래와 같은 순서로 이루어진다.

HTML문서의 로드가 끝나고 HTML을 해석(parsing) 하던 도중에 script tag를 만나게 되면 HTML parsing을 멈추고 Rendering Engine은 Javascript Engine에게 javascript를 처리하기 위해 제어권을 넘긴다. javascript의 해석과 실행이 끝났다면 다시 Rendering Engine이 제어권을 가지고 DOM Tree를 계속하여 만들어 나간다.

HTML 로드 ⇒ Parse HTML ⇒ Parse & Execute Javascript ⇒ Parse HTML Again

하지만, 위와 같은 순서로 진행이 된다면 javascript코드가 실행될 시점에 DOM이 완벽하게 생성되지 않아 조작하는데 문제가 생길 수 있다. 이러한 문제점을 해결하기 위해서는 javascript 실행을 지연시킬 수 있는 defer를 이용할 수 있다. defer에 관해서는 아래에서 잠깐 짚고 넘어갈 것이다.

이제 위의 예제 코드가 나타내는 순서를 확인해보자.

Ⅰ) without defer

위에서 언급했듯이 javascript는 HTML 해석 단계에서 javascript를 만나면 HTML해석을 중단하고 Javascript를 로딩 → 해석 → 실행이 끝나고 다시 HTML 해석을 시작한다고 했다.

따라서 해석단계에서 javascript code가 실행되었으므로 첫 번째의 readystate 값은 interactive임을 확인할 수 있다.

문서의 해석이 끝났다는 것은 DOM Tree와 CSSOM Tree의 생성이 완료되었으므로 이 때 DOMContentLoaded가 발생한다. 그리고 필요한 resource들이 모두 로딩되면 readystate 값은 complete 이 된다.

마지막으로 문서에 관한 모든 resource들이 모두 로딩되었다고 판단하면 load 이벤트가 발생한다. load event가 발생하는 것은 DOM조작에 있어서 요소들이 존재함을 보장하는 것 같다.

Ⅱ) with defer

defer를 사용했을 때 결과는 readystate가 interactive인 것을 찾아볼 수 없다. 이는 defer에 관해서 알고 넘어가야 하는데 defer를 사용하게 되면 javascript의 로딩은 비동기 로 이루어지며 DOMContentLoaded event가 발생했을 때javascript의 파싱(해석)과 실행 이 이루어진다. 정리하자면 크게 아래 2가지 특징을 갖는다.

HTML parsing 중 javascript를 만나면 HTML parsing은 non-blocking으로 진행된다. non-blocking으로 진행된다함은 javascript를 비동기적으로 로딩한다는 뜻이다.

javascript의 파싱과 실행은 DOMContentLoaded event가 발생DOM Tree & CSSOM Tree 생성이 완료되었을 때)하고 나서 진행된다.

따라서, javascript의 실행이 DOMContentLoaded event가 발생하는 시점부터 시작되므로 readystate는 complete 밖에 못 본다.

아래는 javascript의 로딩, 해석, 실행 시점을 도식화한 것이다.

2. Mouse Event

eventevent가 발생하는 순간
click사용자가 HTML 요소를 클릭했을 때
dbclick.. 더블클릭했을 때
mousedown.. 딱 누를 때 시점
mouseup.. 딱 뗄 때 시점
mousemove사용자가 HTML 요소 안에서 움직일 때. → 밖에서 움직일 때 X
mouseover마우스가 HTML요소에 진입하는 딱 그 시점
mouseenter마우스가 HTML요소에 진입하는 딱 그 시점
mouseout마우스가 HTML요소 영역을 딱 벗어나는 시점
mouseleave마우스가 HTML요소 영역을 딱 벗어나는 시점

🔥 check mouse event

<button style="font-size: 100px" class="btn">click</button>
["mouseover", "mousedown", "mouseup", "mousemove", "mouseout", "click"].forEach(
  (e) =>
    $button.addEventListener(e, () => console.log(`${e} event is occurred!!`))
);

🤔🤔 Q? mouseover is hover??

⇒ 결론부터 말하자면 아니다 . hover는 mouse가 요소에 내에 존재하는 시점부터 mouse가 떠나는 시점까지 통틀어 hover이다.

⇒ mouseover는 그저 mouse가 요소에 진입하는 딱 그 순간 event가 한 번 일어난다.

‼️ mouseover/mouseout VS mouseenter/mouseleaver

위의 표를 보면 똑같은 동작을 하는 event가 두 개가 존재한다.

하지만 똑같은 동작을 하는 event를 다른 이름으로 만들었을리가 없다.

일단 가장 차이점은 자식 요소를 event가 발생하는 시점에 둘 지 말 지 이다. 이는 설명하는 것보다 예제로 확인하는 것이 훨씬 이해하기 쉽다. 더 공부하면서 알게된 사실이지만 사실상 위의 이유는 event bubbling & capturing 에 있다.

<h2>mouseover/mouseout event!</h2>
    <div class="over-out">
      <div class="over-out--inner">
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Ratione, autem
        sunt! Pariatur debitis cumque corrupti officia, consectetur molestiae
        earum ad, repellendus quisquam error perspiciatis! Autem ut nam omnis
        totam cumque!
      </div>
    </div>
    <h2>mouseenter/mouseleave event!</h2>
    <div class="enter-leave">
      <div class="enter-leave--inner">
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod atque
        tempora molestiae voluptatum corrupti iusto? Ipsum dolorem et sequi, ab
        atque sed nulla obcaecati ea nam repellendus saepe veniam labore!
      </div>
    </div>
const overOutContinaer = document.querySelector(".over-out");
const enterLeaveContinaer = document.querySelector(".enter-leave");

overOutContinaer.addEventListener("mouseover", () =>
  console.log(`mouseover event occurred!!`)
);
overOutContinaer.addEventListener("mouseout", () =>
  console.log(`mouseout event occurred!!`)
);
enterLeaveContinaer.addEventListener("mouseenter", () =>
  console.log(`mouseenter event occurred!!`)
);
enterLeaveContinaer.addEventListener("mouseleave", () =>
  console.log(`mouseleave event occurred!!`)
);

3. Keyboard Event

eventevent가 발생하는 순간
keydown모든 키를 눌렀을 때 발생한다. 하지만, 문자, 숫자, 특수 문자, enter 키를 눌렀을 때 연속적으로 발생하지만 이 외의 키는 딱 한 번만 발생한다.
keypresskeydown과 비슷하지만 문자, 숫자, 특수 문자, enter 키만을 눌렀을 때 발생하며 이 외의 키에 대해서는 발생하지 않는다. 지금은 deprecated 되어 있다. → keydown으로 쓰는 습관을 들이자
keyup누르고 있던 키를 놓았을 때 한 번만 발생한다.

keypress는 지금 deprecated(폐지) 위기에 놓여있어 사용을 지양하고 있으므로, keypress 말고 keydown을 사용하자

keyboard event도 알아보기 위해 예제를 넣어봤다.

<!-- index.html --> 
<input type="text" id="input" />
<h1 id="input-value"></h1>
// index.js
const $input = document.querySelector("#input");
const $h1 = document.querySelector("#input-value");
const $button = document.querySelector("#reset-input");

$input.addEventListener("keydown", (event) => {
  $h1.textContent = `event.key: ${event.key}\tevent.code: ${event.code}`;
});

$button.addEventListener("click", () => ($h1.textContent = ""));

입력한 키에 대한 프로퍼티의 관계는 여기에서 찾아볼 수 있다.

4. Form Event

eventevent가 발생하는 순간
blur모든 키를 눌렀을 때 발생한다. 하지만, 문자, 숫자, 특수 문자, enter 키를 눌렀을 때 연속적으로 발생하지만 이 외의 키는 딱 한 번만 발생한다.
focuskeydown과 비슷하지만 문자, 숫자, 특수 문자, enter 키만을 눌렀을 때 발생하며 이 외의 키에 대해서는 발생하지 않는다. 지금은 deprecated 되어 있다.
change누르고 있던 키를 놓았을 때 한 번만 발생한다.
submitform 요소 내에서 Enter를 누르거나 input 또는 button type이 submit을 클릭했을 때 발생한다.
focusin
focusout

🚀 마치며

📚 참고

mouse-event-reference

mouseover/mouseout vs mouseenter/mouseleave

readystate-DOMContentLoaded

browser-rendering-process

mdn readystatechange

process when go to google

profile
step by step

0개의 댓글