[JavaScript] 이벤트

2020. 7. 7. 12:50 Javascript/JavaScript

이벤트


1. 이벤트란?

이벤트(event)는 어떤 사건을 의미한다. 브라우저에서의 사건이란 사용자가 클릭을 했을 '때', 스크롤을 했을 '때', 필드의 내용을 바꾸었을 '때'와 같은 것을 의미한다. 

<!DOCTYPE html>

<html>

<body>

    <!-- 사용자가 클릭했을 때 자바스크립트 함수 실행 -->

    <input type="button" onclick="alert(window.location)" value="alert(window.href)" />

    <input type="button" onclick="window.open('bom.html')" value="window.open('bom.html')" />

</body>

</html>

onclick 속성의 자바스크립트 코드(alert(window.location))는 사용자가 이 버튼을 클릭 했을 '때' 실행된다. 즉 js 개발자는 어떤 일이 발생했을 때 실행 되어야 하는 코드를 등록하고, 브라우저는 그 일이 발생했을 때 등록된 코드를 실행하게 된다. 이러한 방식을 이벤트 프로그래밍이라고 한다.


(1) event target

target은 이벤트가 일어날 객체(button)를 의미한다. 아래 코드에서 타겟은 버튼 태그에 대한 객체가 된다.

<input type="button" onclick="alert(window.location)" value="alert(window.href)" />


(2) event type

이벤트의 종류를 의미한다. 위의 예제에서는 click이 이벤트 타입이다. 그 외에도 scroll은 사용자가 스크롤을 움직였다는 이벤트이고, mousemove는 마우스가 움직였을 때 발생하는 이벤트이다.

이벤트의 종류는 이미 약속되어 있다. 아래 링크는 브라우저에서 지원하는 이벤트의 종류를 보여준다.

https://developer.mozilla.org/en-US/docs/Web/Reference/Events


(3) event handler

이벤트가 발생했을 때 동작하는 코드를 의미한다. 위의 예제에서는 alert(window.location)이 여기에 해당한다. 일반적으로 함수에 많이 쓰인다.


2. 이벤트 핸들러 종류


cf.)

이벤트 타입: click

이벤트 속성: onclick

이벤트 핸들러: whenClick() / 이벤트 타입에 해당하는 이벤트가 발생했을 때 실행되는 함수.

--> 문서 객체에 이벤트에 연결하는 방법을 이벤트 모델이라고 한다.


 이벤트 핸들러

 이벤트 내용

 onclick

 클릭할 때

 ondblclick

 더블클릭할 때

 onkeydown

 키를 눌렀을 때

 onkeypress

 키를 누르고 있을 때

 onkeyup

 눌러진 키를 원래대로 되돌릴 때

 onmousedown

 마우스 버튼을 눌렀을 때

 onmouseup

 마우스 버튼을 뗄 때

 onmouseover

 마우스 포인터가 통과할 때

 onmouseout

 마우스 포인터가 벗어날 때

 onmouse

 마우스 포인터가 이동할 때

 onload

 페이지 읽어올 때

 onunload

 다른 페이지로 이동할 때

 onfocus

 폼 부품이나 창에 초점이 맞춰질 때

 onblur

 폼 부품이나 창으로부터 초점이 벗어날 때

 onsubmit

 폼이 송신될 때

 onreset

 리셋 버튼을 눌렀을 때

 onchange

 입력란의 문자열이나 메뉴에서 선택한 항목에 변화가 있을 때

 onsize

 창의 크기가 변경될 때

 onmove

 창이 이동될 때

 onabor

 그림 읽기를 중단했을 때

 onerror

 파일이 존재하지 않거나 그림 읽기에 실패했을 때

 onselect

 입력란의 문자열이 선택될 때


3. 이벤트 전파(버블링과 캡처링)

캡처링과 버블링이란 개념은 이벤트 전파 방식도 복수의 이벤트가 설치될 경우를 전제로 하므로 addEventListener로 이벤트 등록 방식을 사용할 경우에만 해당한다.
HTML 태그는 중첩되어 있다. 따라서 특정한 태그에서 발생하는 이벤트는 중첩되어 있는 태그들 모두가 대상이 될 수 있다. 이런 경우 중첩된 태그들에 이벤트가 등록 되어 있다면 어떻게 처리 될까? 


<html>
    <head>
        <style>
            html{border:5px solid red;padding:30px;}
            body{border:5px solid green;padding:30px;}
            fieldset{border:5px solid blue;padding:30px;}
            input{border:5px  solid black;padding:30px;}
        </style>
    </head>
    <body>
        <fieldset>
            <legend>event propagation</legend>
            <input type="button" id="target" value="target">          
        </fieldset>
        <script>
        function handler(event){
            var phases = ['capturing', 'target', 'bubbling']
            console.log(event.target.nodeName, this.nodeName, phases[event.eventPhase-1]); //nodeName:input
        }
        document.getElementById('target').addEventListener('click', handler, true);
        document.querySelector('fieldset').addEventListener('click', handler, true);
        document.querySelector('body').addEventListener('click', handler, true);
        document.querySelector('html').addEventListener('click', handler, true);
        </script>
    </body>
</html>
실행결과)
INPUT HTML capturing
INPUT BODY capturing
INPUT FIELDSET capturing
INPUT INPUT target 


event.target.nodeName:INPUT ==> target은 언제나 <input> 태그를 가리킨다. 여러 계층속에서 가장 구체적인 태그가 target이다.
this.nodeName:FIELDSET ==> 이벤트 핸들러가 호출된 태그이다.
phase[event.eventPhase-1]:capturing ==> 부모태그에서 자식태그로 이벤트가 호출되는 방식

이벤트 핸들러가 설치되는 순서: html -> body -> fieldset -> input
--> click 이전의 단계로 document.querySelector('html').addEventListener('click', handler, false); 와 같은 기술 순서와 무관함을 혼동하지 말자.

이벤트가 부모에서부터 발생해서 자식으로 전파되고 있다. 이러한 방식을 capturing이라고 한다. ie 낮은 버전에서는 작동하지 않기 때문에 많이 사용하지는 않는다.

코드를 아래와 같이 변경해보자.
document.getElementById('target').addEventListener('click', handler, false); //false면 버블링으로 변환 
document.querySelector('fieldset').addEventListener('click', handler, false);
document.querySelector('body').addEventListener('click', handler, false);
document.querySelector('html').addEventListener('click', handler, false);
실행결과)
INPUT INPUT target
INPUT FIELDSET bubbling
INPUT BODY bubbling
INPUT HTML bubbling
차이점은 addEventListener의 3번째 인자가 false로 변경 되었다.
이벤트 핸들러가 설치되는 순서가 이전 코드와 반대로 되어 있다.

이번에는 순서가 반대로 되었다. 자식부터 부모로 이벤트가 전파되는 것을 버블링(bubbling)이라고 한다.
이벤트 전파를 중간에 가로막을 수도 있다.
아래처럼 코드를 변경해보자. 
function handler(event){
    var phases = ['capturing', 'target', 'bubbling']
    console.log(event.target.nodeName, this.nodeName, phases[event.eventPhase-1]);
}
function stophandler(event){
    var phases = ['capturing', 'target', 'bubbling']
    console.log(event.target.nodeName, this.nodeName, phases[event.eventPhase-1]);
    event.stopPropagation();
}
document.getElementById('target').addEventListener('click', handler, false);
document.querySelector('fieldset').addEventListener('click', handler, false);
document.querySelector('body').addEventListener('click', stophandler, false);
document.querySelector('html').addEventListener('click', handler, false);
실행결과)
INPUT INPUT target
INPUT FIELDSET bubbling
INPUT BODY bubbling
INPUT HTML bubbling
참고로 ie9 이전의 브라우저에서는 이벤트 전파을 막기 위해서 event.cancelBubble 프로퍼티를 사용해야 한다.


이벤트 전파가 html로 가지 않고 body에서 멈추었다.

4. 기본동작의 취소
웹브라우저의 구성요소들은 각각 기본적인 동작 방법을 가지고 있다.
- 텍스트 필드에 포커스를 준 상태에서 키보드를 입력하면 텍스트가 입력된다.
- 폼에서 submit 버튼을 누르면 데이터가 전송된다.
- a 태그를 클릭하면 href 속성의 URL로 이동한다.
- 이러한 기본적인 동작들을 기본 이벤트라고 하는데 사용자가 만든 이벤트를 이용해서 이러한 기본 동작을 취소할 수 있다.

(1) inline
이벤트의 리턴값이 false이면 기본 동작이 취소된다.
<p>
    <label>prevent event on</label><input id="prevent" type="checkbox" name="eventprevent" value="on" />
</p>
<p>
    <a href="http://opentutorials.org" onclick="if(document.getElementById('prevent').checked) return false;">opentutorials</a>
</p><!--if 조건문이 true라면 return false -->
<p>
    <form action="http://opentutorials.org" onsubmit="if(document.getElementById('prevent').checked) return false;">
            <input type="submit" /><!-- onsubmit: submit(submit 클릭시) 했을때 발생하는 이벤트이다. -->
    </form>
</p>

(2) property 방식
리턴 값이 false이면 기본동작이 취소된다. 
<p>
    <label>prevent event on</label><input id="prevent" type="checkbox" name="eventprevent" value="on" />
</p>
<p>
    <a href="http://opentutorials.org">opentutorials</a>
</p>
<p>
    <form action="http://opentutorials.org">
            <input type="submit" />
    </form>
</p>
<script>
    document.querySelector('a').onclick = function(event){
        if(document.getElementById('prevent').checked)<!-- true 라면 return false-->
            return false;
    };
     
    document.querySelector('form').onclick = function(event){
        if(document.getElementById('prevent').checked)
            return false;
    };
</script>

(3) addEventListener 방식
이 방식에서는 이벤트 객체의 preventDefault 메소드를 실행하면 기본 동작이 취소된다. 
<p>
      <label>prevent event on</label><input id="prevent" type="checkbox" name="eventprevent" value="on" />
</p>
<p>
      <a href="http://opentutorials.org">opentutorials</a>
</p>
<p>
       <form action="http://opentutorials.org">
             <input type="submit" />
       </form>
</p>
<script>
       document.querySelector('a').addEventListener('click', function(event){
              if(document.getElementById('prevent').checked)
              event.preventDefault();
        });
             
        document.querySelector('form').addEventListener('submit', function(event){
             if(document.getElementById('prevent').checked)
             event.preventDefault();
        }); 
</script>
ie9 이하 버전에서는 event.returnValue를 false로 해야 한다.



출처: https://devbox.tistory.com/entry/JavaScript-이벤트?category=574556 [장인개발자를 꿈꾸는 :: 기록하는 공간]