ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 브라우저 이벤트
    FE/HTML 2025. 8. 26. 13:51

    🔍 브라우저 이벤트란?

    브라우저에는 많은 이벤트가 발생합니다.

    • 사용자가 버튼을 클릭
    • 화면의 크기 조절
    • 화면 스크롤
    • 등등

    이처럼 사용자의 인터렉션(이벤트)가 발생하면 그에 해당하는 일을 등록해 처리할 수 있습니다.

    이벤트는 함수에 연결되어 이벤트가 발생하지 전에는 함수가 실행되지 않다가 이벤트가 발생되면 실행됩니다.

    • 이벤트 핸들러

     

    🤖 이벤트 객체

    이벤트가 발생했을 때 브라우저가 자동으로 생성하여 이벤트 핸들러 함수에 전달하는 정보를 담은 객체입니다.

    • 여러 이벤트들의 공통적인 속성과 이벤트 종류에 따른 특정 속성, 메서드를 포함합니다.
    • 이벤트 객체는 이벤트가 발생한 요소, 이벤트 타입, 마우스 좌표, 키보드 입력 등 이벤트와 관련된 정보를 제공합니다.

    📌 주요 속성

    속성 설명 예시
    event.type 이벤트의 종류 ‘click’, ‘keyup’, ‘mousedown’
    event.target 이벤트가 실제로 발생한 요소 버튼 클릭 이벤트 → 클릭된 버튼 요소
    event.currentTarget 이벤트 리스너가 등록된 요소(핸들러가 바인딩된 요소)  
    event.preventDefault() 이벤트의 기본 동작을 막습니다. 링크 클릭 시 페이지 이동 방지
    event.stopPropagation() 이벤트가 캡처링/버블링 단계에서 더 이상 전파되지 않도록 방지 이벤트 흐름 중단, 부모 핸들러 실행 막기
    event.clientX, event.clientY 마우스 이벤트의 경우 뷰 포트 기준 마우스 좌표  
    event.key 키보드 이벤트의 경우 눌린 키 문자열 ‘Enter’, ‘a’

     

     

    🤔 event.target 와 event.currentTarget

    <body>
        <div id="parent">
          부모 요소
          <button id="child">자식 버튼</button>
        </div>
    
        <script>
          const parent = document.getElementById('parent');
    
          // 부모 요소에 클릭 이벤트 리스너 등록
          parent.addEventListener('click', function (event) {
            console.log('event.target:', event.target); // 실제 클릭된 요소
            console.log('event.currentTarget:', event.currentTarget); // 이벤트 리스너가 등록된 요소
          });
        </script>
      </body>

     

    🖥️ 결과

    # 부모 요소 클릭시
    event.target: <div id="parent">…</div>
    event.currentTarget: <div id="parent">...</div>
    
    # 자식 요소 클릭시
    event.target: <div id="child">자식 버튼</div>
    event.currentTarget: <div id="parent">...</div>

     

    📖 특징

    1. 이벤트가 발생할 때마다 새로 생성되어 이벤트 핸들러의 인자로 전달됩니다.
    2. 이벤트 버블링이나 캡처링 단계에서도 동일한 이벤트 객체가 전달되어 이벤트 흐름을 제어하거나 원본 이벤트 요소를 확인 가능.
    3. 이벤트 위임(Event Delegation)에 필수적이며 이벤트 핸들러를 부모 요소에 등록하고 자식 요소에서 발생한 이벤트를 처리할 수 있도록 도와줍니다.

     

    ↗️ 이벤트 전파 흐름

    1️⃣ 캡처링 단계

    • 이벤트가 가장 바깥쪽 조상 요소(예: <html>)에서 시작해 이벤트 발생 요소까지 DOM 트리를 아래로 순차적으로 내려가며 전달됩니다.
    • 이 단계에서 감지하려면 addEventListener의 세 번째 인자 또는 옵션 객체에 capture: true를 설정해야 합니다.

    2️⃣ 타깃 단계

    • 이벤트가 실제로 발생한 타깃 요소에서 핸들러가 실행

    3️⃣ 버블링 단계

    • 타깃 요소에서 이벤트가 시작되어 다시 DOM 트리를 따라 부모 요소로 '거품처럼' 올라갑니다.
    • 부모 요소 더 바깥 요소에 등록된 이벤트 핸들러가 순차적으로 실행됩니다.

     

    🫧 버블링

    <div onclick="alert('!!')">
      <p><span>Test</span></p>
    </div>

    Test 를 클릭했을 때 핸들러가 동작

     

    🤔 왜 <span> 을 클릭했는데 <div>에 할당한 핸들러가 동작하지? → 버블링

     

    버블링

    • 한 요소에서 이벤트가 발생 시 해당 요소에 할당된 핸들러가 동작하고 이어서 부모 요소 핸들러가 동작
    • 마지막 조상 요소를 만날 때까지 반복되면서 요소 각각에 할당된 핸들러가 동작합니다.

     

    🖥️ 예시 - <p> 클릭시

    <form onclick="alert('form')">FORM
      <div onclick="alert('div')">DIV
        <p onclick="alert('p')">P</p>
      </div>
    </form>
    1. <p>에 할당된 onclick 핸들러 동작
    2. <div> 에 할당된 onclick 핸들러 동작
    3. <form>에 할당된 onclick 핸들러 동작

    이벤트가 제일 깊은 요소부터 부모 요소를 거슬러 올라가면서 발생하는 모습 → 물속 거품과 닯았다

     

    🚫 버블링 중단

     

    event.stopPropagation()

    • 핸들러에게 이벤트를 처리하고 난 후 버블링을 중단하도록 하는 명령
    <body onclick="alert(`버블링 안됌`)">
      <button onclick="event.stopPropagation()">중단</button>
    </body>

     

    👻 캡처링

    이벤트가 발생하면 최상위 조상에서 시작해 아래로 전파되어 자식요소의 이벤트도 함께 발생

    element.addEventListener(..., { capture: true })
    • addEventListener의 3번째 매개변수로 true 값을 설정

     

    🖥️ 예시 - id = child 선택

    <div id="ancestor">
        <div id="parent">
               <div id="child"></div>
        </div>
    </div>
    ancestor.addEventListener("click", (e) => {
      console.log('ancestor click');
    }, true)
    
    parent.addEventListener("click", (e) => {
      console.log('parent click');
    }, true)
    
    child.addEventListener("click", (e) => {
      console.log('child click');
    }, true)

     

    결과

    > ancestor click
    > parent click
    > child click

     

    📌 이벤트 종류

    1️⃣ UI 이벤트

    이벤트 설명
    load 웹페에지나 스크립트 로드 완료되었을 경우
    error 브라우저가 자바스크립트 오류를 만났거나 요청한 자원이 존재하지않는 경우
    resize 브라우저 창 크기 조절하는 경우
    scroll 사용자가 페이지를 위 아래로 스크롤하는 경우
    select 텍스트를 선택하는 경우

     

     

    2️⃣ Keyboard 이벤트

    이벤트 설명
    keydown 키를 누르고 있을 경우
    keyup 누르고 있던 키를 뗄 경우 (키에서 손을 뗀 경우)
    keypress 키를 누르고 뗏을 경우 (키가 입력될 때)

     

     

    🤔 keyup 이랑 keypress 차이가 뭐지?

    • keyup은 키보드의 모든 키에 대해 발생하고 키가 올라가는(떼는) 순간 이벤트가 발생
    • keypress는 문자가 입력되는 키에 대해서만 발생하며 비문자 키에는 반응하지 않습니다.
      • ex) 쉬프트 키나 방향키에는 이벤트가 발생하지 않습니다.
    • 키보드 입력 처리 시 keyup은 키를 뗐을 때 동작하므로 입력 완료 직후에 처리할 때 사용되고 keypress는 키가 눌리는 동안 반복 발생할 수 있어 글자 입력 감지에 주로 씁니다

     

    3️⃣ Mouse 이벤트

    이벤트 설명
    click 마우스 버튼을 클릭했을 경우
    mousemove 마우스를 움직일 경우
    mouseover 마우스를 요소 위로 움직였을 경우

     

    4️⃣ Form 이벤트

    이벤트 설명
    input input 또는 testarea 요소의 값이 변경된 경우
    change select box, checkbox, radion button 상태가 변경된 경우
    submit form 내용을 submit 한 경우 (버튼, 키)
    reset reset 버튼 클릭한 경우

     

    🚀 이벤트 핸들러 등록 방법

    이벤트에 반응하기 위해서는 이벤트가 발생했을 때 실행되는 함수인 핸들러를 등록해야 합니다.

    핸들러는 여러 가지 방법으로 할당할 수 있습니다.

     

    1️⃣ 인라인 이벤트 핸들러

    HTML 태그의 속성으로 직접 함수를 등록하는 방식입니다.

    <button onclick="alert('버튼을 클릭!')">버튼</button>
    • HTML과 JS가 혼합되어 있어 여러 이벤트 처리 시 코드가 지저분해질 수 있음.
    • 요소마다 직접 작성해야 하고 유지보수 어려움.

    script 안에서 함수를 만들고 태그안에 지정할 수도 있습니다.

    <button onclick="handler()">버튼2</button>
    
    <script>
      function handler() {
        alert('handler!!');
      }
    </script>

     

    2️⃣ 프로퍼티 리스너 방식

    이벤트 대상에 해당하는 객체의 프로퍼티로 이벤트를 등록하는 방식

    • 이벤트에 오직 하나의 이벤트 핸들러만을 바인딩할 수 있다.

     

    <button class="btn">Click</button>
    <script>
        const btn = document.querySelector('.btn');
        btn.onclick = function() {
            alert('Button click event handler1');
        };
    
        btn.onclick = function() {
            alert('Button click event handler2');
        };
    </script>

     

    이벤트 핸들러 프로퍼티 방식은 이벤트에 하나의 이벤트 핸들러만을 바인딩 할 수 있어 위 코드에서 두번째 바인딩된 이벤트 핸들러만이 실행된다.

     

    3️⃣ addEventListener

    대상 DOM 요소에 이벤트를 바인딩하고 해당 이벤트가 발생했을 때 실행될 콜백 함수 지정

     

     

    🤔 왜 AddEventListener 를 사용?

    장점 설명
    여러 이벤트 핸들러 지정 하나의 이벤트에 여러 개의 이벤트 핸들러를 등록할 수 있습니다.
    이벤트 해제 및 제거 removeEventListener를 사용해 특정 시점에 이벤트를 제거하거나 필요하지 않을 때 이벤트 리스너를 해제하는데 유용
    캡처링 버블링 지원 캡처링, 버블링을 지정해 이벤트 전파를 세밀하게 제어할 수 있습니다.

     

    😎 이벤트 핸들러 내부의 this

     

    1️⃣ 인라인 이벤트 핸들러

    <button onclick="inline()">Button</button>
    
    <script>
        function inline () {
          console.log(this);
        }
    </script>
    
    --------결과--------
    Window {window: Window, self: Window, document: document, name: '', location: Location, …}

    인라인 이벤트 핸들러는 HTML 속성 안에 직접 작성된 자바스크립트 코드로 브라우저가 이를 기본적으로 일반 함수처럼 호출합니다.

    • 일반 함수는 호출할 때 어떤 객체에도 묶여 있지 않은 상태이기 때문에 this는 전역 객체인 window를 참조합니다.

     

    2️⃣ 프로퍼티 리스너 방식

    <button class="btn">Button</button>
    
    <script>
      const btn = document.querySelector('.btn');
    
      btn.onclick = function (e) {
        console.log(this);
        console.log(e.currentTarget);
        console.log(this === e.currentTarget);
      };
    </script>
    
    ------결과------
    <button class="btn">Button></button>
    <button class="btn">Button></button>
    true

    프로퍼티 방식에서 이벤트 핸들러는 이벤트 핸들러가 요소의 메서드처럼 호출됩니다.

    • 따라서 element.onclick()과 유사하게 호출되어 this가 해당 요소(element)를 가리키게 됩니다.
    • 이벤트 객체의 currentTarget과 this가 일치

     

    3️⃣ addEventListener

    <button class="btn">Button</button>
    
    <script>
        const btn = document.querySelector('.btn');
    
        btn.addEventListener('click', function (e) {
          console.log(this); 
          console.log(e.currentTarget);
          console.log(this === e.currentTarget);
        });
    </script>
    
    ------결과------
    <button class="btn">Button></button>
    <button class="btn">Button></button>
    true

    addEventListener에 등록된 함수는 이벤트가 발생한 요소에 바인딩된 콜백 함수로 호출됩니다.

    • 즉, 내부적으로 handler.call(element)와 같이 호출되어 this가 이벤트 대상 요소를 가리킵니다.
    • 이벤트 객체의 currentTarget과 this가 일치

     

    🔖 이벤트 위임

    요소마다 핸들러를 할당하지 않고 하나의 부모 요소에서 이벤트 핸들러를 단 하나만 할당

    • 캡처링과 버블링을 활용

     

    부모 요소에서 할당한 핸들러에서 event.target 을 이용하면 실제 이벤트를 발생시킨 요소를 확인할 수 있습니다.

    <body>
      <button id="addItemBtn">항목 추가</button>
      <ul id="itemList">
        <li data-id="1">아이템 1</li>
        <li data-id="2">아이템 2</li>
        <li data-id="3">아이템 3</li>
      </ul>
    
      <script>
        const itemList = document.getElementById('itemList');
        let count = 3;
    
        // 부모 요소에 이벤트 리스너 등록 (이벤트 위임)
        itemList.addEventListener('click', function (event) {
          if (event.target.tagName.toLowerCase() === 'li') {
            alert(`클릭한 항목: ${event.target.textContent} (id: ${event.target.dataset.id})`);
          }
        });
    
        // 버튼 클릭 시 새 항목 추가 (동적 생성 요소도 위임 가능)
        document.getElementById('addItemBtn').addEventListener('click', () => {
          count++;
          const li = document.createElement('li');
          li.textContent = `아이템 ${count}`;
          li.dataset.id = count;
          itemList.appendChild(li);
        });
      </script>
    </body>
    • ul#itemList 에 클릭 이벤트 리스너를 한 번만 등록합니다.
    • 클릭된 실제 대상(event.target)이 li 요소인지 확인 후 처리
    • 새로 추가된 항목들도 각각 개별 리스너 없이 부모 리스너에 의해 처리
    • 이렇게 이벤트 위임으로 다수의 자식 요소 이벤트를 효과적으로 관리할 수 있습니다.

     

    📖 DOM APIs

    JavaScript를 통해 DOM API로 DOM을 조작함으로써 웹 페이지의 동적인 요소를 만들 수 있습니다.

     

    🧩 DOM 요소 선택

    DOM을 조작하기 위한 첫 단계는 원하는 HTML 요소를 선택하는 것입니다.

    API 설명 특징
    document.getElementById() HTML 요소의 고유한 id 속성 값을 사용해 특정 요소를 찾습니다. id는 페이지내에서 유일해 하나의 요소만 반환합니다.
    document.querySelector() CSS 선택자 문법을 사용해 DOM에서 가장 먼저 일치하는 요소 하나를 찾습니다. 클래스, ID, 태그명 등 다양한 CSS 선택자를 사용할 수 있어 원하는 요소를 쉽게 찾을 수 있습니다.
    document.querySelectorAll() CSS 선택자에 일치하는 모든 요소를 NodeList 객체로 반환합니다. NodeList는 배열과 유사하지만 일부 배열 메서드만 사용할 수 있습니다.

     

     

     

    🧩 노드 속성 정보 얻기 - Properties

    선택된 DOM 요소의 다양한 정보를 얻을 수 있습니다.

    API 설명
    element.tagName 요소의 HTML 태그 이름을 대문자 문자열로 반환
    element.textContent 해당 요소와 자식 요소의 모든 텍스트 콘텐츠를 반환
    element.nodeType 노드의 타입을 숫자로 반환 (1: element 노드, 3: text 노드)

     

    🧩 DOM 탐색

    API 설명
    element.childNodes 모든 자식 노드(Element 및 Text 노드 포함)를 NodeList로 반환합니다.
    element.firstChild 첫 번째 자식 노드를 반환합니다. 공백, 줄바꿈도 텍스트 노드로 간주되어 주의해야 합니다.
    element.firstElementChild 첫 번째 요소노드를 반환합니다. 공백 등을 무시하고 실제 태그만 찾을 때 유용합니다.
    element.parentElement 부모 요소 노드를 반환합니다.
    element.nextSibling 바로 다음 형제 노드를 반환합니다.
    element.nextElementSibling 바로 다음 형제 요소(Element) 노드를 반환합니다
    element.closest(selector) 현재 요소부터 시작해 부모 방향으로 탐색하며 주어진 CSS 선택자와 가장 가까이 일치하는 조상 요소를 반환합니다.

     

    🧩 DOM 조작

    DOM 요소를 추가, 삭제, 교체하는 방법입니다.

     

    📖 기본적인 조작 API

    API 설명
    removeChild(child) 특정 자식 노드를 제거
    appendChild(child) 특정 부모 노드의 마지막 자식으로 노드를 추가
    insertBefore(newNode, rNode) rNode 앞에 새로운 노드를 삽입
    cloneNode() 노드를 복제
    replaceChild(newChild, oldChild) 기존 자식 노드를 새로운 노드로 교체

     

     

    📖 문자열 기반의 쉬운 조작

    브라우저에서 DOM을 직접 조작할 때는 createElement, appendChild 같은 노드 단위 조작이 있고 innerHTML 같은 문자열 기반 조작이 있습니다.

     

    1️⃣ innerText

    • 값 가져오기: element 안의 text 값들만 가져옵니다.
    • 값 설정하기: html을 포함한 문자열을 입력하면 html 코드가 문자열 그대로 element에 포함됩니다.
    • 요소의 텍스트 콘텐츠만 다룸 (HTML 태그는 그대로 문자열로 처리)
    const div = document.querySelector("#myDiv");
    
    console.log(div.innerText);  // 요소 안의 텍스트 반환
    div.innerText = "새 텍스트";  // 텍스트만 변경

     

    2️⃣ innerHTML

    • 값 가져오기: element 안의 HTML / XML을 가져옵니다.
    • 값 설정하기: html 코드 입력시 html element가 element안에 포함
    • 요소의 HTML 전체 문자열 반환 / 설정
    • 문자열을 파싱해서 DOM 트리로 변환
    • 기존 자식 노드를 모두 교체
    const div = document.querySelector("#firstDiv");
    
    console.log(div.innerHTML);
    // "<span>Hello</span>" 같은 HTML 문자열 반환
    
    div.innerHTML = "<b>굵은 글씨</b>";
    // 기존 내용 사라지고 새로운 HTML 반영

     

    3️⃣ insertAdjacentHTML(position, text)

    • 기존 DOM 을 덮어쓰지 않고 지정한 위치에 HTML 문자열 삽입
    • position 값
      • "beforebegin" : 요소 바깥, 앞
      • "afterbegin" : 요소 안쪽, 첫 번째 자식 앞
      • "beforeend" : 요소 안쪽, 마지막 자식 뒤
      • "afterend" : 요소 바깥, 뒤
    const div = document.querySelector("#firstDiv");
    
    // div 안에 <span> 삽입
    div.insertAdjacentHTML("afterbegin", "<span>Hi!</span>");
    
    // div 뒤에 <p> 삽입
    div.insertAdjacentHTML("afterend", "<p>끝!</p>");

     

    📖 템플릿 리터럴(Template Literal)

     

    JavaScript의 템플릿 리터럴(Template Literal) 문법을 사용하면 쉽게 HTML 문자열을 만들 수 있습니다.

    const user = {
       name : "beomsic"
    }
    
    // 백틱(`)을 사용하여 변수를 ${...} 안에 추가
    const result = `
      <div>
        <p>
          Hello! ${user.name}
        </p>
      </div>
    `;
    
    console.log(template); 

     

    'FE > HTML' 카테고리의 다른 글

    CSS 알아보기  (2) 2025.08.25
    브라우저 렌더링 방식 (SSR, CSR)  (0) 2025.08.20
    브라우저 렌더링 과정  (4) 2025.08.19
    HTML 기본 정리  (1) 2025.08.18

    댓글

Designed by Tistory.