Javascript_이벤트(Event)

재이·2022년 2월 4일
0

Javascript

목록 보기
5/7

※ 본 포스팅은 책『실전 프로젝트 반응형 웹 퍼블리싱』의 내용을 토대로 작성됨

이벤트(Event)

우리가 사용하는 브라우저들은 사용자가 띄운 웹 문서를 그 구성과 내용에 맞게 객체화하여 각 요소별(버튼, 이미지 등)로 구조화한다. 각 요소들은 상, 하위 구조나 병렬구조 등으로 체계화되는데 이렇게 정리된 체계를 소위 DOM(Document Object Model, 문서 객체 구조) 이라고 부른다. 자바스크립트는 브라우저가 생성한 이 DOM 구조를 통해 각 요소와의 상호작용을 가능하게 함으로써 웹 페이지가 보다 인터렉티브하게 작동하도록 돕는 것이다.

이런 DOM 구조와의 상호작용에서 가장 빈번하게 사용되는 방법이 바로 '이벤트'이다. 웹 브라우저에서 일어나는 모든 행동들을 '이벤트(Event)'라고 하는데, 우리는 실제 앞에서 '클릭(Onclick)'이라는 이벤트를 사용해 보기도 했다. 이렇게, 특정 이벤트가 발생하는 시점에서 함수를 호출하거나 스크립트를 실행하게 하는 요소를 '이벤트 핸들러'라고 부른다.

그럼 다양한 이벤트 종류에 대해 표로 정리해 보자.

onload --- 문서를 모두 불러오고 나서 발생
onunload --- 문서를 종료할 때 발생
onclick --- 대상을 클릭했을때 발생
ondblclick --- 대상을 더블 클릭했을 때 발생
onkeypress --- 키보드를 눌렀을 때 발생
onkeydown --- 키보드를 눌렀을 때 발생
onkeyup --- 키보드를 누르고 떼었을 때 발생
onmouseover --- 대상에 마우스를 올렸을 때 발생
onmouseout --- 대상에서 마우스가 벗어났을 때 발생
onfocus --- 대상에 포커스가 생겼을 때 발생
onblur --- 대상에서 포커스를 잃었을 때 발생
onsubmit --- 전송(sibmit)버튼을 눌렀을 때 발생
onreset --- 취소(reset)버튼을 눌렀을 때 발생
onchange --- 입력요소의 값이 바뀌고, 포커스가 옮겨졌을 때 발생
onmousemove --- 마우스를 움직일 때마다 발생
onresize --- 브라우저의 창을 조절할 때마다 발생
onerror --- 문서나 이미지를 불러올 때 에러가 나면 발생
onabort --- 문서를 불러오다가 중단되면 발생

이벤트 핸들러 사용법

이벤트 행들러를 사용하는 방법에는 태그에 직접 입력해서 사용하는 '행 입력형' 방식과 태그와 완전히 분리를 해서 사용하는 '외부 분리형' 방식이 있다. 2가지 중 어떤 것을 사용해도 크게 상관은 없지만 혹시 스크립트를 모르는 개발자가 잘못 건드리면 작동하지 않을 수도 있으므로 관리 차원에서 아예 분리하여 <body> 영역 밖으로 빼는 것이 좋다.

이벤트 행 입력형 방식

<body>
  <button onclick="alert('javascript')">버튼</button>
</body>

이벤트 분리형 방식

수정 전(잘못된 사용)

<script type="text/javascript">
  //<![CDATA[
	function theFnc(){
	  alert("javascript");
	}
	var myBtn = document.getElementById("btn1");			// 1. 요소선택
	myBtn.onclick = theFnc;									// 2. 버튼 클릭 시 theFnc 함수 호출
  //]]>
</script>
</head>
<body>
  <button id = "btn1">버튼</button>
</body>
  • var myBtn = document.getElementById("btn1");
    현재 html문서에 자바스크립트 선언문이 <body>보다 위에 있으므로 getElementById 선택자를 이용해서 요소를 가지고 올 수 없다. 그럼 어떻게 해야 할까? 현재 문서의 요소들을 모두 로딩된 후에 선택자를 실행하면 해결되겠다.

  • myBtn.onclick = theFnc;
    선택한 버튼 요소를 클릭했을 때 theFnc함수를 호출한다.

수정 후(올바른 사용)

<script type="text/javascript">
  //<![CDATA[
	function theFnc(){
	  alert("javascript");
	}
	window.onload = function(){							// 브라우저 요소를 모두 불러온 뒤에 함수 실행!
      var myBtn = document.getElementById("btn1");
      myBtn.onclick = theFnc;
    }
  //]]>
</script>
  • window.onload = function(){ 실행문; }
    현재 브라우저의 모든 요소들을 로딩한 후에 함수문을 실행하라는 의미이다. 말 그대로, 함수의 실행을 <body>에 담긴 문서 내용 모두가 로드된 후로 미워두라는 것인데, 이렇게 수정하면 앞서 진행한 '행 입력형 방식'과 동일한 결과화면을 얻을 수 있다.

기존 방식(DOM Level 0) 이벤트의 문제점

위의 예와 같이, 객체에 이벤트를 직접 연결하여 작동하게 하는 고전적인 방식을 'DOM Level 0'이라고 한다. 객체 하나와 이벤트 하나를 연결하여 작동하는 이 방식은 한 객체에 동시에 같은 이벤트를 두 번 이상 적용할 수 없다는 문제를 안고 있다. 한 객체에 같은 이벤트를 두 번 이상 적용하게 되면 제일 마지막에 적용된 이벤트만 실행되는 것이다.

<script type="text/javascript">
  //<![CDATA[
  function theFnc(){
    alert("javascript");
  }
  window.onload = function(){						// 1. window 객체에 onload 이벤트 적용(작동 X)
    var myBtn = document.getElementById("btn1");
    myBtn.onclick = theFnc;
  }
  window.onload = function(){						// 2. 같은 객체에 동일 이벤트 적용(작동 O)
    var myBtn = document.getElementById("btn2");
    myBtn.onclick = theFnc;
  }  
  //]]>
</script>
</head>
<body>
  <button id="btn1">버튼1</button>
  <button id="btn2">버튼2</button>
</body>

위 예제에서는 'window' 객체에 'onload' 이벤트 핸들러가 2번 적용되었다. 그러므로 마지막에 적용된 이벤트만 실행된다.

DOM Level 2 방식 이벤트

한 객체에 같은 이벤트를 두 번 적용할 수 없는 'DOM Level 0'방식의 불편함을 해결하기 위해 개발된 방식이 바로 'Level 2'이다. 하지만 W3C(국제 웹 컨소시업)의 '웹 표준안'과 다른 독자정 구현 방식을 가진 마이크로소프트(Microsoft)社의 '익스플로러(MS Explorer, 이하 IE)'가 가장 많은 사용자를 지닌 사실상의 '표준 브라우저'로 지위를 갖게 되면서, 정확한 이벤트 구현을 위한 이벤트 등록 메서드가 서로 달라진다는 불편함이 생겼다.

결국, DOM Level 2 방식으로 구현한 이벤트를 모든 웹 사용자에게 정확하게 보이려면 표준(W3C)을 따르는 크롬, 파이어폭스, 사파리 등이나 비표준 방식으로 작동하는 IE8 이하 버전의 브라우저 등에서 모두 정상 작동하도록 구분자(if/else if)를 나눠 작성해야 한다.

표준(크롬, 파이어폭스 등)과 비표준(IE8 이하)을 구분하는 이벤트 등록은 다음과 같다.

if(window.addEventListener){ --- 표준 방식 브라우저(크롬, 파이어폭스 등)일 경우
표준 이벤트 등록 메서드;
}else if(window.attachEvent){ --- 비표준 방식 브라우저(IE8 이하)일 경우
비표준 이벤트 등록 메서드;
}

표준 방식의 브라우저인 경우 window.addEventListener에 이벤트 등록 메서드가 존재하며, IE8 이하 버전의 경우에는 window.attachEvent에 이벤트 등록 메서드가 존재한다. 다시 말해, 사용자의 브라우저가 표준 방식이라면 if문, 비표준 방식 브라우저라면 else if문을 만족하도록 작성하는 것이다.

표준 방식 브라우저(파이어폭스/크롬/사파리)에 대한 이벤트 등록방법

이벤트대상.addEventListener("이벤트명", 함수명, false)

가령, 특정 '버튼'을 '클릭'했을 때 'theFnc라는 함수를 호출'하고 싶다면, 이벤트대상은 그 '버튼'이고, 이벤트명은 'click'이며, 호출할 함수명은 'theFnc'가 되는 것이다.

마지막 인자값 false는 이벤트 요소가 위, 아래로 나열될 때 해당 이벤트를 끝내고 다음 이벤트로 넘기는 역할을 한다. 인자값 false가 포함되면 해당 이벤트가 발생한 위치에서 멈추고 아래로 진행되는데, 이를 '버블업' 방식이라고 부른다.

비표준 방식 브라우저(IE8 이하)에 대한 이벤트 등록방법

이벤트대상.attachEvent("on" + "이벤트명", 함수명)

여기서 주의할 점은 인자값에 이벤트명을 입력할 떄 'on'을 붙여야 한다는 것이다. 그리고 버블방식의 설정(false)은 필요 없다.

다음은 앞에서의 DOM Level0 코드를 DOM Level2 이벤트 방식으로 바꿔 본 것이다.

<script type="text/javascript">
  //<![CDATA[
  function theFnc(){
    alert("javascript");
  }
  function clickBtn1() {
    var myBtn1 = document.getElementById("btn1");
    myBtn1.onclick = theFnc;
  }
  function clickBtn2() {
    var myBtn2 = document.getElementById("btn2");
    myBtn2.onclick = theFnc;
  }
  if(window.addEventListener) {							// 1. 표준 방식 브라우저일 경우 실행
    window.addEventListener("load", clickBtn1, false);
    window.addEventListener("load", clickBtn2, false);
  }else if(window.AttachEvent) {						// 2. 비표준 방식 브라우저의 경우 실행
    window.attachEvent("onload", clickBtn1);
    window.attachEvent("onload", clickBtn2);
  }
  //]]>
</script>

window.addEventListener("load", clickBtn1, false);
window.attachEvent("onload", clickBtn1);

㉠, ㉡의 이벤트 등록 메서드들은 모두 "브라우저에 모든 요소들을 로딩한 후에 clickBtn1 함수를 실행하라"는 뜻이다. ㉠방식은 IE8이하에서는 지원되지 않으므로, 표준/비표준 등에 상관없이 모든 브라우저를 지원하기 위해서는 2가지 방식을 모두 등록해야 한다.

이벤트 객체 생성 및 속성

'이벤트 객체' 란 이벤트 핸들러가 구동될 때 생성되는 객체로서 '클릭'이나 '키보드 입력' 등의 동작 자체를 의미한다. 따라서 이벤트 객체에는 좌표나 특정 버튼입력 등에 관한 다양한 속성들이 존재하는데, 이러한 속성들을 활용하면 마우스를 클릭했을 때의 위치 정보는 물론 키보드의 특정 키 입력에 대한 키 코드값 또한 알 수 있다.

이벤트 객체 생성

선택대상.onclick = function(매개변수) {
매개변수(이벤트 객체).속성
}

특정 이벤트 핸들러를 구동하면, 함수의 매개변수에 이벤트 객체가 자동으로 생성된다. 단, 이는 사용자의 브라우저가 W3C의 표준안을 따르는 브라우저일 경우에 한한다. 즉, 비표준 방식의 브라우저(IE8 이하)를 사용 중이라면, 위와 같은 작성 방법만으로는 이벤트 핸들러를 구동하는 것만으로 매개변수에 객체를 자동 생성할 수 없다.

그러므로 보통의 경우, 앞에서 학습한 '조건 연산자'를 사용하여 이벤트 객체의 자동 생성 유·무를 먼저 매개변수에 확인한 후 생성되지 않은(IE8 이하) 경우라면 IE8 전용 이벤트 객체인 'window.event'를 강제 생성하도록 작성한다.

그럼, '조건 연산자'의 사용법을 다시 한 번 간단히 살펴본 후 모든 브라우저에서 이벤트 객체가 자동적으로 생성되도록 작성해 보겠다.('이벤트 객체 생성'의 호환성 유지)

조건 연산자(삼항 조건문)
조건식을 만족(true)하면 실행문1, 그렇지 않으면(false) 실행문2를 수행시키는 조건문

| 기본형식 |

조건식 ? 실행문1 : 실행문2


<예>

var obj = "자바스크립트";
var theText = obj ? obj : "제이쿼리";
document.write(theText);

위와 같은 조건문을 작성한다고 가정하면, 현재 obj 변수에 '자바스크립트'라는 특정 값을 넣었으므로 'var theText = obj?'라는 조건식의 결과값은 true이다. 따라서, theText 변수에는 obj 변수의 값 '자바스크립트'가 저장되는 것이다.

이제, <예> 의 방식을 '이벤트 객체 생성(선택대상, 핸들러 = function(매개변수))'에 적용하는 원리는 다음과 같다.

조건 연산자를 활용하여 매개변수의 값 유·무를 확인한다. 즉, 표준 브라우저라면 생성식의 이벤트 핸들러만으로 이벤트 객체가 생성되었을 것이므로 그 변수값 그대로를 유지시키고, 비표준 방식의 브라우저(IE8 이하), 즉 이벤트 객체가 생성되지 않아 매개변수의 값이 없는 경우라면 그 변수값으로 'window.event'라는 이벤트 객체를 강제로 생성시킨다.

| 기본형식 |
선택대상.onclick = function(e) {
theEvent = e ? e : window.event;
console.log(theEvent.속성);
}


<예>

document.onclick = function(e) {
  theEvent = e ? e : window.event;
  console.log(theEvent.clientX);
}

앞의 <예> 는 다음과 같은 과정을 의미한다. 만약 표준 방식의 브라우저라면 웹 문서 내에서 '클릭'이벤트가 발생할 때에 이벤트 객체가 생성되어 매개변수에 담기고, 생성된 이벤트 객체는 조건 연산자의 조건식을 만족시켜 theEvent 변수로 저장된다. 물론, IE8 이하의 브라우저라면 강제 생성된 window.event 객체가 theEvent 변수에 저장되겠다. 이렇게 저장된 변수에 'clientX'라는 속성을 적용하여 현재 클릭한 마우스의 X값을 출력한 예이다.

이벤트 객체 속성

keydown, keypress

  • alrKey --- 키보드의 [alt]키가 눌렸을 때 true값 반환
  • shiftKey --- 키보드의 [shift]키가 눌렸을 때 true값 반환
  • ctrlKey --- 키보드의 [ctrl]키가 눌렸을 때 true값 반환
  • keyCode --- 입력된 문자키의 고유한 유니코드값을 반환한다.

click, mousemove, mouseover, mouseup, mousedown

  • clientX --- 현재 문서 기준, 이벤트가 발생한 X좌표(스크롤바 너비 계산 X)
  • clientY --- 현재 문서 기준, 이벤트가 발생한 Y좌표(스크롤바 높이 계산 X)
  • screenX --- 모니터 기준, 이벤트가 발생한 X좌표
  • screenY --- 모니터 기준, 이벤트가 발생한 Y좌표
  • pageX --- 현재 문서 기준, 이벤트가 발생한 X좌표(스크롤바 너비 계산 O)
  • pageY --- 현재 문서 기준, 이벤트가 발생한 Y좌표(스크롤바 높이 계산 O)
  • layerX --- position 속성값이 'absolute'인 레이어 안에서의 상대 X좌표
  • layerY --- position 속성값이 'absolute'인 레이어 안에서의 상대 Y좌표
  • target --- 이벤트가 발생한 대상 요소
  • button --- 마우스 버튼(왼쪽/오른쪽/휠)의 클릭된 상태 체크

all

  • type --- 이베트의 종류
<head>
  <script type="text/javascript">
  //<![CDATA[
	document.onmouse = function(e) {
	  var theEvent = e ? e : window.event;				// 1. 이벤트 객체 생성
	  var myForm = document.form1;

	  // 2. 이벤트 속성 - 문서 기준으로 좌표를 구함.
	  myForm.clt_x.value = "clientX: " + theEvent.clientX;
	  myForm.clt_y.value = "clientY: " + theEvent.clientY;

	  // 3. 이벤트 속성 - 스크린(모니터)기분으로 좌표를 구함.
	  myForm.scr_x.value = "screenX: " + theEvent.screenX;
	  myForm.scr_y.value = "screenY: " + theEvent.screenY;

	  // 4. 이벤트 속성 - 문서 기준으로 스크롤바 높이까지 계산해 좌표를 구함.
	  myForm.pg_x.value = "pageX: " + theEvent.pageX;
	  myForm.pg_y.value = "pageY: " + theEvent.pageY;
	}
  //]]>
  </script>
</head>
<body>
  <form name = "form1" action = "#">
    <p><input type="text" name="clt_x" id="clt_x" /></p>
    <p><input type="text" name="clt_y" id="clt_y" /></p>
    <p><input type="text" name="src_x" id="src_x" /></p>
    <p><input type="text" name="src_y" id="src_y" /></p>
    <p><input type="text" name="pg_x" id="pg_x" /></p>
    <p><input type="text" name="pg_y" id="pg_y" /></p>
  </form>
</body>
  • theEvent.clientY 와 theEvent.pageY 차이점
    페이지에서 가로/세로 스크롤바가 발생했을 경우, client는 그 스크롤바 높이를 계산하지 않고, page는 스크롤바 높이까지 계산하여 각각 위치값을 구한다.

  • theEvent.screenX
    모니터 좌측 상단을 기준으로 좌표값을 구한다.

앞의 예제는 자바스크립트를 통해 사용자의 마우스 움직임에 따라 상호작용하는 예를 보인 간단한 예이다. 이렇게, 자바스크립트를 활용하면 사용자의 입력(키보드/마우스)에 따라 반응하는 재미있는 페이지를 구성해낼 수 있다.

비 IE 계열 브라우저들만의 전용 속성 pageX, pageY
이벤트 객체의 속성 중 'pageX'와 'pageY'는 비 IE 계열 브라우저(파이어폭스, 크롬 등)들만의 전용 속성으로, 만약 위의 코드를 IE에서 실행하면 pageX와 pageY의 값은 모두 'underfined(확인되지 않음)'로만 출력된다.

그럼, 이번에는 사용자의 키보드 입력에 반응하는 예를 작성해 보겠다. 다음은 특정 키코드값을 추적하여 이를 활용한 단축키(조합)의 작동을 구현한 예제이다.

<script type="text/javascript">
  //<![CDATA[
    document.onkeydown = function(e) {
  	  var theEvent = e ? e : window.event;			// 1. 이벤트 객체 생성
  	  var theKey1 = theEvent.keyCode;				// 2. 키코드 생성
  	  var theKey2 = theEvent.shiftKey;				// 3. 키보드 상의 [shift] 키의 눌림 여부
  
  	  if(theKey1 == 72 && theKey2){					// 4. [shift] + [H] 누르면 조건문 실행
        alert("단축키 완성")
      }
	}
  //]]>
</script>
profile
그림쟁이 개발자

0개의 댓글