본문 바로가기
WEB/JavaScript

[JavaScript] 이벤트 (Event)

by Amy IT 2022. 7. 3.

 

목차

     

     

    이벤트와 이벤트 핸들러

    이벤트(event)란 프로그래밍하고 있는 시스템에서 일어나는 사건(action) 혹은 발생(occurrence)입니다. 버튼을 클릭하거나 키보드를 입력하는 등 사용자가 이벤트를 발생시킬 수도 있고, 페이지가 로드되는 등 어플리케이션 스스로가 이벤트를 발생시킬 수도 있습니다.

    웹 페이지 안에서 발생한 여러 가지 이벤트를 이벤트 핸들러(event handler)를 이용해 처리할 수 있습니다. 이벤트 핸들러는 이벤트에 대응해 이벤트 처리를 담당하는 함수로서, 이벤트 리스너(event listener)라고도 합니다. 이벤트 처리를 위해 이벤트 핸들러를 정의하는 것을 이벤트 핸들러를 등록(register)했다고 말합니다.

     

     

     

    이벤트와 이벤트 핸들러 연결

    이벤트와 이벤트 핸들러를 연결하기 위한 방법은 크게 DOM Level 0 과 DOM Level 2 두 가지로 나뉩니다. DOM Level 0 방법으로는 인라인 이벤트 핸들러 방식, 이벤트 핸들러 프로퍼티 방식 있고, DOM Level 2 방법으로는 addEventListener 메소드 방식이 있습니다. 

     

    인라인 이벤트 핸들러

    HTML 태그의 속성(attribute)에 이벤트 속성을 추가하는 방법입니다. 이벤트명 앞에 on 접두사를 붙여 사용합니다. 자바스크립트 코드와 HTML이 혼합되기 때문에 비권장되는 방법입니다.

    <!-- script 부분 -->
    <script type="text/javascript">
    function test() {  //click 이벤트 발생시 처리할 함수 등록
    	console.log("클릭!!");
    }
    </script>
    <!-- body 부분 -->
    <button onclick="test()">버튼</button>

     

    이벤트 핸들러 프로퍼티

    HTML과 분리하여 스크립트 코드에서 DOM 객체의 프로퍼티(property)를 이용하는 방법입니다. 대상 DOM 요소에 on 접두사를 붙인 이벤트명으로 이벤트 핸들러 프로퍼티를 설정하고 이벤트 발생시 처리할 함수를 등록합니다. 

    <!-- script 부분 -->
    <script type="text/javascript">
    window.onload = init; //윈도우가 모두 로드되었을 때 실행할 함수 등록
    function init() {
    	var btn = document.getElementById("btn");
    	btn.onclick = function () { //click 이벤트 발생시 처리할 함수 등록
    		console.log("버튼 클릭!");
    	}
    }
    </script>
    <!-- body 부분 -->
    <button id="btn">버튼</button>

     

    addEventListener() 메소드

    이미지 출처 https://poiemaweb.com/js-event

    addEventListener() 메소드 방식 (표준 이벤트 모델)입니다. addEventListener() 메소드를 이용하여 대상 DOM 요소에 이벤트를 설정하고 해당 이벤트가 발생했을 때 실행될 이벤트 핸들러를 등록합니다. 이는 더 현대적인 방식으로서, 앞선 두 가지 방식보다 이점을 가지고 있습니다. 인라인 이벤트 핸들러 방식, 이벤트 핸들러 프로퍼티 방식은 각 요소에 이벤트 타입별로 하나의 이벤트 핸들러만 연결할 수 있는 반면, addEventListener() 메소드 방식은 여러 개의 이벤트 핸들러를 연결할 수 있습니다. 또한, 이전에 추가한 이벤트 핸들러를 제거하는 removeEventListener()라는 대응 관계에 있는 함수가 제공됩니다.

    <!-- script 부분 -->
    <script type="text/javascript">
    window.onload = function () {
    	var btn = document.getElementById("btn");
    	btn.addEventListener("click", function () { //click 이벤트 발생시 처리할 함수 등록
    		console.log("버튼 클릭!");
    	});
    }
    </script>
    <!-- body 부분 -->
    <button id="btn">버튼</button>

     

     

     

    주요 이벤트

    분류 이벤트명 발생 타이밍 주된 대상 요소
    읽기 abort 이미지의 로딩이 중단되었을 때 img
    load 페이지, 이미지의 로딩 완료 시 body, img
    unload 다른 페이지로 이동할 때 body
    마우스 click 마우스 클릭 시  
    dblclick 더블클릭 시  
    mousedown 마우스 버튼을 눌렀을 때  
    mousemove 마우스 포인터가 이동했을 때  
    mouseout 요소에서 마우스 포인터가 떨어졌을 때  
    mouseover 요소에 마우스 포인터가 겹쳤을 때  
    mouseup 마우스 버튼을 떼어 놓았을 때  
    contextmenu context menu가 표시되기 전 body
    keydown 키를 눌렀을 때  
    keypress 키를 누른 상태  
    keyup 키를 떼어 놓았을 때  
    change 내용이 변경되었을 때 input(text), select
    reset 리셋 버튼이 눌렸을 때 form
    submit 서브밋 버튼이 눌렸을 때 form
    포커스 blur 요소로부터 포커스가 벗어났을 때  
    focus 요소가 포커스되었을 때  
    그 외 resize 요소의 사이즈를 변경했을 때  
    scroll 스크롤했을 때 body

     

    마우스 - click, mouseover, mouseout

    * 버튼 이용 click, mouseover, mouseout

    <!-- script -->
    <script type="text/javascript">
    window.onload = function () {
    	var btn = document.getElementById("btn");
    	btn.addEventListener("click", function () {
    		document.getElementById("result").innerText = "클릭 이벤트 발생";
    	});
    	btn.addEventListener("mouseover", function () {
    		document.getElementById("result").innerText = "마우스오버 이벤트 발생";
    	});
    	btn.addEventListener("mouseout", function () {
    		document.getElementById("result").innerText = "마우스아웃 이벤트 발생";
    	});
    }
    </script>
    <!-- body -->
    <button id="btn">버튼</button><br>
    <div id="result">결과</div>

     

    * 전체 선택, 선택한 체크박스 이용 결과 출력

    <!-- script -->
    <script type="text/javascript">
    var arr;
    window.onload = function () {
    	arr = document.getElementsByClassName("fruits");
    	document.getElementById("selectAll").addEventListener("click", check, false);
    	document.getElementById("show").addEventListener("click", show, false);
    }
    function check() {
    	for (var i = 0; i < arr.length; i++) {
    		arr[i].checked = this.checked;
    	}
    }
    function show() {
     	var result = "";
     	for (var i = 0; i < arr.length; i++) {
     		if (arr[i].checked) {
     			result += arr[i].value+"&nbsp;&nbsp;";
     		}
     	}
     	document.getElementById("result").innerHTML = result;
    }
    </script>
    <!-- body -->
    과일 선택하기<br>
    전체선택<input type="checkbox" id="selectAll"><br>
    사과<input type="checkbox" class="fruits" name="fruits" value="apple">/
    바나나<input type="checkbox" class="fruits" name="fruits" value="banana">/
    망고<input type="checkbox" class="fruits" name="fruits" value="mango"><br>
    <button id="show">결과보기</button><br>
    <div id="result"></div>

     

    키 - keyup

    * 길이 검사

    <!-- script -->
    <script type="text/javascript">
    window.onload = function () {
    	var minUseridLength = 6;
    	var userid = document.getElementById("userid");
    	var idMsg = document.getElementById("idMsg");
    	
    	function checkLength(n) {
    		idMsg.innerText = '';
    		if (userid.value.length < n) {
    			idMsg.innerText = "아이디는 "+ n +"자 이상이어야 합니다.";
    		}
    	} 
    	
    	userid.addEventListener("keyup", function () {
    		checkLength(minUseridLength);
    	}); 
    }
    </script>
    <!-- body -->
    아이디 <input type="text" name="userid" id="userid">
    <span id="idMsg"></span><br>

     

    폼 - change, submit, reset

    * 드롭다운 리스트(select 태그)로 색 변경하기

    <!-- script -->
    <script type="text/javascript">
    window.onload = function () {
    	var color = document.getElementById("color");
    	var result = document.getElementById("result");
    	color.addEventListener("change", function () {
    		result.style = "color:"+this.value;
    	});
    }
    </script>
    <!-- body -->
    <select name="color" id="color">
    	<option>red</option>
    	<option>blue</option>
    	<option>green</option>
    </select><br>
    <span id="result">result</span>

     

    * 로그인 폼 submit 시 조건 검사

    <!-- script -->
    <script type="text/javascript">
    window.onload = function () {
    	var login = document.querySelector("#login");
    	login.addEventListener("submit", check);
    	function check() {
    		var userid = document.querySelector("#userid");
    		var userpw = document.querySelector("#userpw");
    		var idCheck = document.querySelector("#idCheck");
    		var pwCheck = document.querySelector("#pwCheck");
    		if (userid.value.length == 0) {
    			idCheck.innerText = "아이디를 확인하세요.";
    			event.preventDefault();
    		} else if (userpw.value.length == 0) {
    			idCheck.innerText = '';
    			pwCheck.innerText = "비밀번호를 확인하세요.";
    			event.preventDefault();
    		}
    	}
    }
    </script>
    <!-- body -->
    <form id="login" action="target.html">
    	아이디 <input type="text" name="userid" id="userid">
    	<span id="idCheck"></span><br>
    	비밀번호 <input type="password" name="userpw" id="userpw">
    	<span id="pwCheck"></span><br>
    	<button>로그인</button>
    </form>

     

    * reset 시 확인창 띄우기

    <!-- script -->
    <script type="text/javascript">
    window.onload = function () {
    	var text = document.getElementById("text");
    	text.addEventListener("reset", function () {
    		if (!confirm("정말 지우시겠습니까?")) {
    			event.preventDefault();
    		}
    	});
    }
    </script>
    <!-- body -->
    <form id="text" action="#">
    	<textarea rows="10" cols="20"></textarea>
    	<input type="reset" value="지우기">
    </form>

     

     

     

    이벤트 핸들러 함수 내부의 this

    인라인 이벤트 핸들러

    인라인 이벤트 핸들러 방식에서 이벤트 핸들러 함수를 호출하며 this를 전달할 수 있습니다. 이벤트 핸들러 함수의 매개변수가 받는 인자는 이벤트에 바인딩된 요소, 즉 현재 이벤트가 발생한 요소가 됩니다.

    <button onclick="foo(this)">버튼</button>
    <script type="text/javascript">
    function foo(c) {
    	console.log(c); //<button onclick="foo(this)">버튼</button>
    }
    </script>

     

    이벤트 핸들러 프로퍼티

    이벤트 핸들러 프로퍼티 방식에서 이벤트 핸들러 내부의 this는 이벤트에 바인딩된 요소를 가리킵니다. 이는 이벤트 객체의 currentTarget 프로퍼티와 같습니다.

    <button>버튼</button>
    <script type="text/javascript">
    var btn = document.querySelector("button");
    btn.onclick = function (e) {
    	console.log(this); //<button>버튼</button>
    	console.log(e.currentTarget); //<button>버튼</button>
    	console.log(this === e.currentTarget); //true
    }
    </script>

     

    addEventListener() 메소드

    addEventListener 메소드에서 지정한 이벤트 핸들러 내부의 this 역시 이벤트 리스터에 바인딩된 요소를 가리키며, 이벤트 객체의 currentTarget 프로퍼티와 같습니다.

    <button>버튼</button>
    <script type="text/javascript">
    var btn = document.querySelector("button");
    btn.addEventListener("click", function (e) {
    	console.log(this); //<button>버튼</button>
    	console.log(e.currentTarget); //<button>버튼</button>
    	console.log(this === e.currentTarget); //true
    });
    </script>

     

     

     

    Event 객체

    Event 객체는 이벤트를 발생시킨 요소와 발생한 이벤트에 대한 유용한 정보를 제공합니다. 이벤트가 발생하면 Event 객체는 동적으로 생성되며 이벤트 핸들러에 암묵적으로 인자로 전달됩니다. 

     

    Event 객체 프로퍼티

    프로퍼티 설명
    target 실제로 이벤트를 발생시킨 요소를 가리킴
    currentTarget 이벤트에 바인딩된 DOM 요소를 가리킴
    type 발생한 이벤트의 종류를 나타내는 문자열을 반환
    keyCode 발생한 키보드 이벤트의 ASCII 값을 반환 (deprecated)
    key / code 발생한 키보드 이벤트의 키 값을 반환
    cancelable 요소의 기본 동작을 취소시킬 수 있는지 여부(true/false)를 나타냄
    eventPhase 이벤트 흐름(event flow) 상에서 어느 단계(event phase)에 있는지를 반환
    (0 : 이벤트 없음 / 1 : 캡쳐링 단계 / 2 : 타깃 / 3 : 버블링 단계)

     

     

     

    이벤트 흐름

    이미지 출처 https://poiemaweb.com/js-event

    계층적 구조에 포함되어 있는 HTML 요소에 이벤트가 발생할 경우 연쇄적 반응이 일어납니다. 즉, 이벤트가 전파(Event Propagation)되는데 전파 방향에 따라 버블링(Event Bubbling)과 캡처링(Event Capturing)으로 구분할 수 있습니다. 이벤트가 처음 발생되면 DOM의 최상위 객체인 Document 객체로 이벤트가 전달됩니다. 발생된 이벤트는 다음의 과정을 거쳐 전파됩니다. 

     

    1. 이벤트 캡처링 : Document 부터 아래로 내려가서 이벤트 발생요소의 부모객체까지 전달됩니다.
    2. 이벤트 타겟 : 이벤트 발생요소까지 전달됩니다.
    3. 이벤트 버블링 : 이벤트 발생요소의 부모로부터 위로 Document 까지 거슬러 올라갑니다.

     

    버블링과 캡처링은 둘 중에 하나만 발생하는 것이 아니라 캡처링부터 시작하여 버블링으로 종료합니다. addEventListener 메소드의 세번째 매개변수에 true를 설정하면 캡처링으로 전파되는 이벤트를 캐치하고, false 또는 미설정하면 버블링으로 전파되는 이벤트를 캐치합니다.

     

     

     

    기본 동작의 변경

    Event.preventDefault()

    폼을 submit하거나 링크를 클릭하면 다른 페이지로 이동하게 됩니다. 이와 같이 요소가 가지고 있는 기본 동작을 중단시키기 위해 preventDefault() 메소드를 사용할 수 있습니다.

    <a href="http://www.google.com">google</a>
    <script type="text/javascript">
    	document.querySelector("a").addEventListener("click", function () {
    		if (!confirm("정말 이동하시겠습니까?")) {
    			event.preventDefault();
    		}
    	});
    </script>

     

    Event.stopPropagation()

    이벤트가 발생한 자식 요소로부터 부모 요소로 이벤트가 전파되는 것(버블링)을 중단시키기 위한 메소드입니다. 아래 코드에서 event.stopPropagation() 이 없는 경우, b를 클릭하면 b가 클릭됐다는 메세지와 a가 클릭됐다는 메세지가 모두 출력됩니다. 이는 자식인 b에서 발생한 클릭 이벤트가 부모인 a로 전파되어 a에서도 클릭 이벤트에 대한 처리가 이루어진 것입니다. 이러한 이벤트의 전파를 중단시키기 위해 event.stopPropagation()을 사용합니다. 

    <div id="a" style="background-color: #FF0000">
    	a
    	  <div id="b" style="background-color: #00FF00">
    	  	b
    	  </div>
    </div>
    <script type="text/javascript">
    	var a = document.getElementById("a");
    	a.addEventListener("click", function () {
    		console.log("a 클릭됨!");
    	}, false);
    
    	var b = document.getElementById("b");
    	b.addEventListener("click", function () {
    		console.log("b 클릭됨!");
    		event.stopPropagation(); //이벤트 전파 방지
    	}, false);
    </script>

     

    preventDefault & stopPropagation

    return false를 사용하면 기본 동작의 중단과 버블링 또는 캡처링의 중단을 동시에 실시할 수 있습니다. 단 이 방법은 인라인 이벤트 핸들러 방식에서만 적용 가능합니다.

    <a href="http://www.google.com" onclick="return handleEvent()">google</a>
    <script type="text/javascript">
    	function handleEvent() {
    		if (!confirm("정말 이동하시겠습니까?")) {
    			return false;
    		}
    	}
    </script>

     

     

     

    참고

    https://developer.mozilla.org/ko/docs/Learn/JavaScript/Building_blocks/Events

    https://poiemaweb.com/js-event

     

     

     

    댓글