이벤트의 흐름
HTML 요소는 다른 요소의 내부에 중첩된다. 그래서 링크에 마우스를 가져가거나 클릭하면 그 부모 요소에도 마우스를 가져가거나 클릭한 셈이 된다.
이벤트 버블링
이벤트가 사용자의 동작에 직접적으로 영향을 받은 특정 노드로부터 시작하여 가장 무관한 요소를 향해 바깥으로 전파되어 나가는 방식이다. 대부분의 브라우저가 기본적으로 지원하는 방식이다.
<a> => <li> => <ul> => <body> => <html>
이벤트 캡쳐링
이벤트가 가장 바깥쪽의 노드로부터 시작해서 안쪽으로 전파되어 들어오는 방식이다.
<html> => <body> => <ul> => <li> => <a>
현재의 모든 브라우저들은 기본적으로 이벤트 캡쳐링 대신 이벤트 버블링을 사용한다. 리스너를 사용하는 경우 addEventListener () 메서드의 마지막 매개변수에 설정하는 값에 따라 발생한 이벤트의 전파 방향을 선택할 수 있다.
.html
<body>
<div id="page">
<h1>List King</h1>
<h2>Bubble</h2>
<ul id="list">
<li id="item"><a id="link">fresh figs</a></li>
</ul>
</div>
<div id="page">
<h1>List King</h1>
<h2>Capture</h2>
<ul id="list2">
<li id="item2"><a id="link2">fresh figs</a></li>
</ul>
</div>
<script src="js/event-flow.js"></script>
</body>
.js
function showElement() {
alert(this.innerHTML);
}el = document.getElementById("list");
el.addEventListener('click', showElement, false);
el = document.getElementById("item");
el.addEventListener('click', showElement, false);
el = document.getElementById("link");
el.addEventListener('click', showElement, false);
el = document.getElementById("list2");
el.addEventListener('click', showElement, true);
el = document.getElementById("item2");
el.addEventListener('click', showElement, true);
el = document.getElementById("link2");
el.addEventListener('click', showElement, true);
<버블 출력 순서>
1.fresh figs
2.<a id="link">fresh figs</a>
3.<li id="item"><a id="link">fresh figs</a></li>
event 객체
event 객체는 이벤트가 발생했을 때 이벤트를 발생시킨 요소와 발생한 이벤트에 대한 정보를 제공한다. 제공하는 정보는 다음과 같다.
*이벤트를 발생시킨 요소
*keypress 이벤트가 어떤 키에 의해 발생했는지 대한 정보
*사용자가 뷰포트 내의 어떤 요소를 클릭해서 click 이벤트가 발생했는지에 대한 정보
*event 객체는 이벤트 핸들러나 리스너로 지정된 함수에 전달된다.
매개변수가 없는 이벤트 리스너
function checkUsername(e){
var target = e.target; //이벤트가 발생한 요소를 가져 온다.
}
var el = document.getElementById(‘username’);
el.addEventListener(‘blur’,checkUsername,false);
//특별한 작업을 하지 않더라도 event 객체에 대한 참조는 1번과정에서 이벤트 핸들러가 함수를 호출할 때 자동으로 전달된다.
//이벤트 객체도 메서드와 속성이 있다.
매개변수를 가진 이벤트 리스너
function checkUsername(e,minLength){
var target = e.target; //이벤트가 발생한 요소를 가져 온다.
}
var el = document.getElementById(‘username’);
el.addEventListener(‘blur’,function(e){
checkUsername(e,5);
},false);
ie5-ie8 브라우저의event 객체
function checkLength(e, minLength) { // 함수 선언
var el, elMsg; // 변수 선언
if (!e) { // event 객체 존재하지 않으면
e = window.event; // ie를 위한 우회 방법 적용
}
el = e.target || e.srcElement; // 이벤트가 발생한 요소를 가지고 온다.
elMsg = el.nextSibling; // 이웃 요소를 가져온다.
if (el.value.length < minLength) { // 이름이 너무 짧으면 메시지를 설정한다.
elMsg.innerHTML = 'Username must be ' + minLength + ' characters or more';
} else { //그렇지 않으면
elMsg.innerHTML = ''; // 메시지를 제거한다.
}
}
var elUsername = document.getElementById('username'); //요소를 가져온다.
if (elUsername.addEventListener) { // 이벤트 리스너가 지원되면
elUsername.addEventListener('blur', function(e) { // blur 이벤트를 처리한다.
checkLength(e, 5); // 함수를 호출한다.
}, false); // 이벤트를 버블링한다.
} else { // 그렇지 않으면
elUsername.attachEvent('onblur', function(e) { // ie로 간주하고 onblur 이벤트처리
checkLength(e, 5); // 함수 호출
});
}
이벤트 위임
이벤트 리스너를 지정하는 요소가 많을수록 페이지의 실행 속도는 느려진다.
그러나 이벤트의 흐름을 이용하면 부모 요소를 이용하여 이벤트의 발생을 대기할 수 있다.
이벤트는 이벤트를 포함하고 있는 부모 요소에도 영향을 미치기 때문에 자식요소를 포함할 수 있는 부모요소에 이벤트핸들러를 지정하고 event 객체의 target 속성을 이용하여 정확히 어떤 요소에서 이벤트가 발생했는지를 판단하면 된다.
장점
새로운 요소들과도 잘 동작한다.
dom트리에 새로운 요소를 추가해도 이벤트에 대한 처리는 부모에게 위임 되었기 때문에 새로운 요소에 이벤트 핸들러를 다시 지정할 필요가 없다.
this 키워드의 제약을 해결한다.
코드가 간편해 진다.
기본동작 변경하기
preventDefalt() 메서드
사용자가 링크를 클릭하거나 폼을 제출해도 계속 같은 페이지에 머무르게 할 때 사용
ie5-ie8 브라우저는 returnValue라는 속성에 false를 지정하는 방법을 대신 사용한다. 이 경우 조건문을 이용하여 preventDefault() 메서드가 지원되는지 확인한 후, 메서드가 제공되지 않으면 ie8 방법을 사용한다.
if(event.preventDefault){
event.preventDefault();
}else {
event.returnValue = false;
}
stopPropagation() 메서드
어느 한 요소를 이용해서 이벤트를 처리하고 나면 이벤트가 부모 요소로 버블링 되는데 이것을 중단할 때 사용한다.
ie8 이하 버전에서는 cancelBuble 속성에 true를 지정하는 방법을 대신 사용한다.
if(event.stopPropagation){
eventstopPropagation();
}else {
event.cancelBuble = true;
}
두 메서드 모두 사용
return false;
이렇게 하면 요소의 기본 동작을 중단함과 동시에 이벤트가 버블링 되거나 캡쳐링 되는 것도 중단할 수 있다. 이 방법은 모든 브라우저에 보편적으로 사용된다.
알아둘점은 자바스크립트 해석기가 return false 구문을 만나게 되면 이후 코드의 실행을 중단하고 함수를 호출한 문장의 다음 문장을 실행한다는 점이다.
즉, 함수 내에서 이후의 코드를 실행하지 않게 되므로 경우에 따라서 false를 리턴하는 것 보다 preventDefault() 메서드를 사용하는 것이 나을 때도 있다.
이벤트 위임의 활용
.html
<body>
<div id="page">
<h1>List King</h1>
<h2>Buy groceries</h2>
<ul id="shoppingList">
<li class="complete"><a href="itemDone.php?id=1"><em>fresh</em> figs</a></li>
<li class="complete"><a href="itemDone.php?id=2">pine nuts</a></li>
<li class="complete"><a href="itemDone.php?id=3">honey</a></li>
<li class="complete"><a href="itemDone.php?id=4">balsamic vinegar</a></li>
</ul>
</div>
<script src="js/event-delegation.js"></script>
</body>
.js
function getTarget(e) { // 함수 선언
if (!e) { //event 객체가 존재하지 않으면
e = window.event; // ie의 event 객체를 사용한다.
}
return e.target || e.srcElement; // 이벤트가 발생한 요소를 가져온다.
}
function itemDone(e) { // 함수 선언
// 목록에서 아이템을 제거한다.
var target, elParent, elGrandparent; //변수를 선언한다.
target = getTarget(e); //링크가 클릭된 아이템을 가져온다.
if ( target.nodeName.toLowerCase() == "a" ) { // 선택한 요소 이름이 a 면
elListItem = target.parentNode; // 부모 요소를 가져온다. li
elList = elListItem.parentNode; // 부모의 부모 요소를 가져온다. ul
elList.removeChild(elListItem); // li 제거
}
if ( target.nodeName.toLowerCase() == "em" ) {
elListItem = target.parentNode.parentNode;
elList = elListItem.parentNode;
elList.removeChild(elListItem);
}
//링크의 기본 동작이 실행되지 않도록 한다.
if (e.preventDefault) { // preventDefault()메서드가 동작하면
e.preventDefault(); // 메서드를 사용한다.
} else { // 그렇지 않으면
e.returnValue = false; // ie의 속성을 사용한다.
}
}
//click 이벤트가 발생하면 itemDone() 함수를 호출하도록 이벤트 리스너를 지정한다.
var el = document.getElementById('shoppingList');// 물품 목록을 가져 온다.
if (el.addEventListener) { // 이벤트 리스너가 지원되면
el.addEventListener('click', function(e) { //click 이벤트에 리스너를 지원한다.
itemDone(e); // itemDone() 메서드를 호출한다.
}, false); // 이벤트 버블링을 사용한다.
} else { // 그렇지 않으면
el.attachEvent('onclick', function(e) { // onclick 이벤트를 사용한다.
itemDone(e); // itemDone()메서드 호출
});
}
어떤 요소에서 이벤트가 발생했을까?
이벤트 핸들러 함수가 호출될 때 어떤 요소에서 이벤트가 발생했는지 알아내는 최고의 방법은 event 객체의 target 속성을 참조하는 방법이다. 그러나 아래의 예제에서 볼 수 있듯이 이 속성은 this 키워드와 관련이 있다.
this 키워드
this키워드는 함수의 소유자를 참조한다. 아래 예제 코드에서 this 키워드는 이벤트가 발생한 요소를 참조한다. 이 방법은 함수에 매개변수를 전달하지 않는 경우에만 제대로 동작한다.
function checkUsername(){
var elMsg = document.getElementById(‘feedback’);
if(this.value.length<5){
elMsg.innerHTML = “이름이 짧습니다.”;
}else{
elMsg.innerHTML = ‘’ ;
}
}
var el = document.getElementById(‘username’);
el.addEventListennr(‘blur’,checkUsername,false);
매개변수 사용하기
이벤트 핸들러 함수에 매개변수를 전달하려면 해당 함수를 익명함수로 둘러싸야 하며, 그렇기 때문에 this 키워드는 이제 이벤트가 발생한 요소가 아닌 익명 함수를 가리키게 된다. 이런경우에는 이벤트가 발생한 요소를 다른 매개 변수를 이용하여 전달한다.
function checkUsername(el,minLength){
var elMsg = document.getElementById(‘feedback’);
if(el.value.length<5){
elMsg.innerHTML = “이름이 짧습니다.”;
}else{
elMsg.innerHTML = ‘’ ;
}
}
var el = document.getElementById(‘username’);
el.addEventListennr(‘blur’,function(){
checkUsername(el,5);
},false);
이벤트의 종류
사용자 인터페이스
사용자 인터페이스 이벤트는 브라우저가 로드한 HTML 페이지가 아닌 브라우저 창을 사용할 때 발생하는 이벤트들이다.
예를 들어, 페이지가 로드되었다거나 브라우저 창의 크기가 조정된 경우에 발생하는 이벤트들을 의미한다.
ui 이벤트를 처리하기 위한 핸들러/리스너는 브라우저 창에 바인딩되어야 한다.
이벤트 | 발생시점 | 브라우저 지원 |
load | 웹페이지의 로드가 완료되었을 때 발생한다. 또한 이미지 스크립트 혹은 객체등 다른 요소의 노드들이 로드 되었을 때도 발생한다. | window객체에서 발생 |
unload | 웹페이지가 새로운 페이지로 이동할 때 발생한다. | window객체에서 발생 |
error | 브라우저가 자바스크립트 오류를 발견했거나 존재하지 않는 자원을 발견했을 때 발생한다. |
|
resize | 브라우저 창의 크기가 변경되었을 때 |
|
scroll | 스크롤 할 때 발생 |
|
load 이벤트 예)
load 이벤트는 페이지의 콘텐츠에 접근하기 위한 코드를 실행할 때 주로 사용한다.
이 예제는 setup() 함수를 호출하여 페이지가 로드되었을 때 자동으로 텍스트 입력 필드에 포커스가 이동하도록 한다.
이 이벤트는 페이지가 html 이나 이미지, css, 스크립트 로드를 완료하면 window 객체에 의해서 자동으로 발생한다.
setup() 함수는 포커스를 이동하기 위해 id 특성 값이 username인 요소를 찾으려고 하기 때문에 페이지가 로드되기 전까지는 실행되어서는 안된다.
load 이벤트는 페이지가 가지고 있는 모든 요소(이미지 , 스크립트)들이 전부 로드되었을때만 발생하기 때문에 스크립트가 실행되기 전에 사용자가 어떤 동작을 수행할 수도 있다.
사용자들은 스크립트에 의해 페이지의 모습이 바뀌거나 포커스가 이동하거나 또는 이미 사용했던 폼 요소가 다시 선택되는 등의 현상을 보고 비로소 스크립트가 실행 되기 시작했음을 알게 된다.
document 객체를 이용하면 브라우저간 호환성 이슈가 발생할 수 있기 때문에 window객체에 바인딩 했다.
<script>요소를 html 페이지의 아랫부분에 정의 하면 dom은 스크립트를 실행하기에 앞서 폼 요소를 먼저 로드하므로 이 경우 load 이벤트의 발생을 기다릴 필요가 없다.
.html
<body>
<div id="page">
<h1>List King</h1>
<h2>New Account</h2>
<form method="post" action="http://www.example.org/register">
<label for="username">Create a username: </label>
<input type="text" id="username" /><div id="feedback"></div>
<label for="password">Create a password: </label>
<input type="password" id="password" />
<input type="submit" value="sign up" />
</form>
</div>
<script src="js/load.js"></script>
</body>
.js
function setup() { // 함수 선언
var textInput; // 변수를 생성
textInput = document.getElementById('username'); // 요소를 가져 온다.
textInput.focus(); // 요소에 포커스를 지정한다.
}
window.addEventListener('load', setup, false); // 페이지가 로드되면 setup() 호출
focus 와 blur 이벤트
사용자가 상호작용을 할 수 있는 링크나 폼 요소 같은 html 요소는 포커스를 받을 수 있다.
이런 요소들은 자신이 포커스를 갖거나 잃을 때 이벤트를 발생시킨다.
사용자가 폼의 요소들과 상호작용을 할 때 도움말이나 피드백을 제공하고자 하는 경우
사용자가 폼을 제출할 때까지 기다리는 대신 어느 한 요소에서 다른 요소로 이동했을 때 유효성 검사를 수행할 필요가 있는 경우
이벤트 | 발생시점 | 흐름 |
focus | 요소가 포커스를 받았을 때 dom노드에서 focus 이벤트가 발생한다. | 캡처 |
blur | 요소가 포커스를 잃을 때 dom노드에서 blur 이벤트가 발생한다. | 캡처 |
focusin | focus 동일 | 버블&캡쳐 |
focusout | blur 동일 | 버블&캡쳐 |
예)
텍스트 입력 필드가 포커스를 받거나 잃을 때 마다 입력 필드 아래의 div 요소에 도움말을 표시한다.
.html
<body>
<div id="page">
<h1>List King</h1>
<h2>New Account</h2>
<form method="post" action="http://www.example.org/register">
<label for="username">Create a username: </label>
<input type="text" id="username" /><div id="feedback"></div>
<label for="password">Create a password: </label>
<input type="password" id="password" />
<input type="submit" value="sign up" />
</form>
</div>
<script src="js/focus-blur.js"></script>
</body>
.js
function checkUsername() {
var username = el.value;
if (username.length < 5) {
elMsg.className = 'warning'; // class특성변경
elMsg.textContent = 'Not long enough, yet...';// 메시지 수정
} else { // 그렇지 않으면
elMsg.textContent = ''; // Clear the message
}
}function tipUsername() { // 함수 선언
elMsg.className = 'tip'; // class 특성 변경
elMsg.innerHTML = 'Username must be at least 5 characters';
}var el = document.getElementById('username'); // 입력 요소 찾기
var elMsg = document.getElementById('feedback'); // 메시지를 저장할 요소 찾기
// 요소가 포커스를 받거나 잃을 때 위의 함수 호출
el.addEventListener('focus', tipUsername, false);
el.addEventListener('blur', checkUsername, false);
마우스 이벤트
마우스를 움직이거나 버튼을 클릭했을때
이벤트 | 발생시점 | 터치 환경 |
click | 사용자가 마우스로 어떤 요소를 클릭했을 때,또 사용자가 포커스를 가진 요소에서 키보드의 엔터키를 눌렀을때도 발생한다. |
|
dbclick | 두 번클릭했을 때 발생 |
|
mousedown | 마우스를 누르고 있는 동안 발생 | touchstar이벤트 발생 |
mouseup | 사용자가 마우스 버튼을 놓을 때 발생 | touchend 이벤트가 발생 |
mouseover | 마우스 커서가 요소의 바깥에서 안으로 이동할 때 발생 |
|
mouseout | mouseover와 반대 |
|
mousemove | 요소의 영역내에서 마우스를 움직일 때 |
|
예)
-click 이벤트를 이용하여 페이지에 추가된 큰 공지사항 레이어를 제거하는 기능을 구현. 우선 스크립트를 이용하여 공지사항 레이어를 페이지에 추가
공지사항을 닫기 위한 링크에서 click 이벤트가 발생하면 dismissNode() 함수를 호출한다. 이 함수는 스크립트에 의해 추가되었던 노트를 제거한다.
.html
<body>
<div id="page">
<h1>List King</h1>
<h2>New Account</h2>
<form method="post" action="http://www.example.org/register">
<label for="username">Create a username: </label>
<input type="text" id="username" /><div id="feedback"></div>
<label for="password">Create a password: </label>
<input type="password" id="password" />
<input type="submit" value="sign up" />
</form>
</div>
<script src="js/click.js"></script>
</body>
.js
// 메시지를 위한 html 코드 작성
var msg = '<div class=\"header\"><a id=\"close\" href="#">close X</a></div>';
msg += '<div><h2>정기 정검 중입니다.</h2>';
msg += '오전 3시에 서버 정검이 있습니다. ';
msg += '이 시간 동안 서비스 이용이 블가능 합니다.</div>';
var elNote = document.createElement('div'); // 새 요소 생성
elNote.setAttribute('id', 'note'); // id 특성을 추가 이름은 note
elNote.innerHTML = msg; // 메시지 출력
document.body.appendChild(elNote); // 공지를 페이지에 추가
function dismissNote() { //함수 정의
document.body.removeChild(elNote); // 공지 레이어 제거
}
var elClose = document.getElementById('close'); // 닫기 버튼 찾는다.
elClose.addEventListener('click', dismissNote, false);
// 닫기 버튼이 클릭되면 공지사항 레이어를 제거한다.
이벤트가 발생한 지점
event 객체는 이벤트가 발생했을 때의 커서의 위치에 대한 정보를 제공한다.
스크린
screenX와 screenY 속성은 모니터 화면 전체를 대상으로 하며, 브라우저가 아닌
화면의 왼쪽 상단 모서리를 기준으로 현재 커서의 위치를 알려준다.
페이지
pageX 와 pageY의 속성은 전체 페이지를 기준으로 현재 커서의 위치를 알려준다.
페이지의 최상단은 뷰포트를 벗어나 있을 수 있기 때문에 커서가 같은 위치에 있다 하더라도 페이지 좌표와 클라이언트 좌표가 다를 수 있다.
클라이언트
clientX와 clientY 속성은 브라우저의 뷰포트를 기준으로 커서의 위치를 알려준다.
예)
.html
<body id="body">
<div id="stats">
screenX: <input type="text" id="sx" />
screenY: <input type="text" id="sy" /><span class="divider">|</span>
pageX: <input type="text" id="px" />
pageY: <input type="text" id="py" /><span class="divider">|</span>
clientX: <input type="text" id="cx" />
clientY: <input type="text" id="cy" />
</div>
<div id="page">
<h1>List King</h1>
<h2>Buy groceries</h2>
<ul>
<li><em>fresh</em> figs</li>
<li>pine nuts</li>
<li>honey</li>
<li>balsamic vinegar</li>
<li>linguine</li>
<li>cream</li>
<li>quinoa</li>
<li>sourdough bread</li>
<li>kale</li>
<li>almond milk</li>
<li>mushrooms</li>
<li>apples</li>
<li>strawberries</li>
<li>rice crackers</li>
<li>brie</li>
<li>rice</li>
</ul>
</div>
<script src="js/position.js"></script>
</body>
.js
var sx = document.getElementById('sx'); // screenX속성 값을 보여줄 요소
var sy = document.getElementById('sy');
var px = document.getElementById('px');
var py = document.getElementById('py');
var cx = document.getElementById('cx');
var cy = document.getElementById('cy');
function showPosition(event) { //함수 선언
sx.value = event.screenX; //screenX값을 출력한다.
sy.value = event.screenY;
px.value = event.pageX;
py.value = event.pageY;
cx.value = event.clientX;
cy.value = event.clientY;
}
var el = document.getElementById('body'); //body요소를 가져 온다.
el.addEventListener('mousemove', showPosition, false); // 이벤트를 바인딩 한다.
키보드 이벤트
사용자가 키보드를 이용할 때 발생한다.
이벤트 | 발생시점 |
input | <input> <textarea> 요소의 값이 변경될 때 마다 발생한다. |
keydown | 키를 누를 때 마다 발생.키를 누르고 있으면 반복해서 발생 |
keypress | 사용자가 키를 눌렀다가 떼어서 문자가 화면에 나타나게 되면 발생 |
keyup | 키를 눌렀다가 뗀후 화면에 문자가 나타난 이후에 발생 |
순서
1.keydown – 사용자가 키를 눌렀다.
2.keypress – 키를 눌렀거나 누르고 있어서 페이지에 문자가 입력되고 있다.
3.keyup- 사용자가 키를 뗐다.
참고
keydown이나 keypress 이벤트에 대한 event객체는 어떤 키가 눌렀는지 알려주는 keyCode 라는 속성을 가지고 있다. 아스키 코드를 리턴한다.
String.fromCharCode(event.keyCode);
예)
- <textarea>요소에 180글자만을 입력할 수 있다. 사용자가 텍스트를 입력하면 스크립트는 앞으로 몇 개의 글자를 더 입력할 수 있는지 보여준다.
이벤트 리스너는 textarea 요소의 keypress 이벤트의 발생을 대기한다. 그리고 발생할 때 마다 charCount() 함수를 호출하여 문자의 개수를 수정하고 마지막에 입력된 문자를 보여준다.
.html
<body>
<div id="page">
<h1>List King</h1>
<form id="messageForm">
<h2>My profile</h2>
<textarea id="message"></textarea>
<div id="charactersLeft">180 characters</div>
<div id="lastKey"></div>
</form>
</div>
<script src="js/keypress.js"></script>
</body>
.js
var el; // 변수 선언
function charCount(e) { // 함수 선언
var textEntered, charDisplay, counter, lastkey; // 변수 선언
textEntered = document.getElementById('message').value; //사용자가 입력한 텍스트
charDisplay = document.getElementById('charactersLeft'); //문자개수를 출력할 요소
counter = (180 - (textEntered.length)); // 입력가능 문자개수
charDisplay.textContent = counter; //남은 문자의 개수
lastkey = document.getElementById('lastKey'); //마지막에 입력된 키얻기
lastkey.textContent = 'Last key in ASCII code: ' + e.keyCode; //
}
el = document.getElementById('message');
// 메시지를 출력할 요소를 찾는다.
el.addEventListener('keyup', charCount, false);
// keypress 이벤트에 charCount() 함수를 바인딩한다.
폼 이벤트
이벤트 | 발생시점 |
submit | 폼 데이터가 서버로 전송될 때 <form> 요소에 해당하는 노드에서는 submit 이벤트가 발생한다.이 이벤트는 사용자가 입력한 값을 서버로 전달하기에 앞서, 입력된 값이 올바른지 검사할 때 주로 이용된다. |
change | 여러개의 폼요소들의 상태가 변경되었을 때 예) 드롭다운 상자에서 항복을 변경했을 때 라디오 버튼을 선택했을 때 체크박스를 선택하거나 해제했을 때 경우에 따라서 click 보다는 change가 사용자에게 유리하다. |
input |
|
예)
사용자가 드롭다운 상자에서 항목을 선택하면 change 이벤트가 발생하여 packageHint() 함수가 호출된다. 이 함수는 사용자의 선택에 따라 메시지를 선택하여 보여준다.
폼 데이터를 서버로 전송하기 전에는 checkTerms() 함수가 호출된다. 이 함수는 사용자가 체크박스를 선택했는지 검사한다.
만일 체크박스를 선택하지 않았으면 폼 요소의 기본 동작을 취소하고 사용자에게 오류 메시지를 보여준다.
.html
<body>
<div id="page">
<h1>List King</h1>
<form method="post" action="http://www.example.org/register" id="formSignup">
<h2>Membership</h2>
<label for="package" class="selectbox"> Select a package: </label>
<select id="package">
<option value="annual">1 year ($50)</option>
<option value="monthly">1 month ($5)</option>
</select>
<div id="packageHint" class="tip"></div>
<input type="checkbox" id="terms" />
<label for="terms" class="checkbox"> Check to agree to terms & conditions</label>
<div id="termsHint" class="warning"></div>
<input type="submit" value="next" />
</form>
</div>
<script src="js/form.js"></script>
</body>
.js
var elForm, elSelectPackage, elPackageHint, elTerms, elTermsHint;
//변수 선언
elForm = document.getElementById('formSignup'); // 요소 저장
elSelectPackage = document.getElementById('package');
elPackageHint = document.getElementById('packageHint');
elTerms = document.getElementById('terms');
elTermsHint = document.getElementById('termsHint');
function packageHint() { // 함수 선언
var pack = this.options[this.selectedIndex].value; // 선택항목 알아내기
if (pack === 'monthly') { // 월단위 패키지면
elPackageHint.innerHTML = 'Save $10 if you pay for 1 year!';
//메시지를 보여준다.
} else { // 아니면
elPackageHint.innerHTML = 'Wise choice!'; // 이 메시지를 보여준다
}
}function checkTerms(event) { // 함수 선언
if (!elTerms.checked) { // 체크박스를 체크하지 않으면
elTermsHint.innerHTML = 'You must agree to the terms.'; //메시지를 보여준다.
event.preventDefault(); // 폼을 전송하지 않는다.
}
}
//이벤트 리스너를 생성한다. submit 이벤트가 발생하면 checkTerms()함수를 호출하고, change이벤트가 발생하면 packageHint()함수를 호출한다.
elForm.addEventListener('submit', checkTerms, false);
elSelectPackage.addEventListener('change', packageHint, false);
변형 이벤트와 관찰자
DOM은 요소가 추가되거나 제거될 때마다 그 구조가 변경된다.
이때 변형 이벤트가 발생한다.
스크립트를 통해 페이지에 콘텐츠를 추가하거나 제거하면 이 과정에서 DOM트리의 변형이 이루어진다. DOM트리의 변형에 대응해야 하는 이유는 여러 가지가 있다.
이벤트 | 발생시점 | |
DOMNodeInserted | dom트리에 노드가 추가될 때마다 발생한다. 즉, appendChild(), replaceChild(), insertBefore(), 메서드를 호출하면 발생 | |
DOMNodeRemoved | 노드가 제거 될 때 마다 발생,removeChild, replaceChild | |
DOMSubtreeModified | dom의 구조가 변경되면 발생. | |
DOMNodeInsertedIntoDocument | 이미 문서에 존재하는 다른 노드의 후손 노드가 dom트리에 추가 될 때 발생 | |
DOMNodeRemovedFromDocument | 이미 문서에 존재하는 다른 노드의 후손 노드가 제거될 때 발생
|
예)
사용자가 새로운 목록 아이템을 추가하기 위해 링크를 클릭했을 때 반응한다.그러면 dom 구조가 변경되어 변형 이벤트가 발생한다.
두 번째 이벤트는 <ul>요소의 dom트리에 변경이 발생할 때까지 대기한다. 그러다가 DOMNodeInserted 이벤트가 발생하면 updateCount() 함수를 호출한다. 이 함수는 목록에 몇 개의 아이템이 있는지 확인하여 페이지 상단에 표시한다.
.html
<body>
<div id="page">
<h1>List King</h1>
<h2>Buy Groceries <span id="counter">1</span></h2>
<ul id="list">
<li>fresh figs</li>
</ul>
<div class="button"><a href="/additem" class="add">Add list item</a></div>
</div>
<script src="js/mutation.js"></script>
</body>
.js
var elList, addLink, newEl, newText, counter, listItems; // 변수선언
elList = document.getElementById('list'); // 목록 얻기
addLink = document.querySelector('a');
// 아이템을 추가하는 버튼 가져온다.
counter = document.getElementById('counter');
// 아이템의 개수를 출력할 요소를 가져온다.
function addItem(e) { // 함수선언
e.preventDefault(); // 링크의 동작 취소
newEl = document.createElement('li'); // 새로운 li 요소 생성
newText = document.createTextNode('New list item'); // 새로운 택스트 노드생성
newEl.appendChild(newText); // <li> 요소에 텍스트 추가
elList.appendChild(newEl); //<li>요소를 목록에 추가
}
function updateCount() { // 함수 선언
listItems = elList.getElementsByTagName('li').length; // <li> 요소 개수 센다
counter.innerHTML = listItems; // 개수 출력
}
addLink.addEventListener('click', addItem, false); // 버튼의 click 이벤트 처리
elList.addEventListener('DOMNodeInserted', updateCount, false);
// DOM 변형 이벤트 처리
html5 이벤트
이벤트 | 발생시점 |
DOMCountentLoaded | dom트리가 형성될 때 발생한다. (이미지, 자바스크립트는 여전히 로딩줄일수 있다. ) load 이벤트에 바인딩 된 이벤트보다 먼저 실행된다. |
hashchange | url의 해시가 변경될 때 발생한다. ajax를 이용하여 콘텐츠를 로드하는 경우에도 사용 |
beforeunload | window 객체에서 발생하며 페이지가 언로드 되기전에 발생한다. 예를 틀어 사용자가 폼데이터를 저장하지 않은 상태에서 다른 페이지로 이동하려고 할 때 알림 메시지 |
예)
- dom트리가 구성되자 마자 id특성 값이 username인 텍스트 입력 필드가 포커스를 가지도록 한다.
- DOMCountentLoaded는 load 이벤트보다 먼저 발생한다. load 이벤트는 페이지의 모든 리소스가 로드될때까지 기다리기 때문이다.
만일 사용자가 저장 버튼을 클릭하기전에 페이지를 이동하려고 한다면 beforeunload를 이용하여 사용자에게 알림 메시지를 보여 줄수 있다.
.html
<body>
<div id="page">
<h1>List King</h1>
<h2>Profile</h2>
<form id="messageForm" action="http://example.org/">
<textarea id="message"></textarea>
<input type="submit" value="next" />
</form>
</div>
<script src="js/html5-events.js"></script>
</body>
.js
function setup() {
var textInput;
textInput = document.getElementById('message');
textInput.focus();
}
window.addEventListener('DOMContentLoaded', setup, false);
window.addEventListener('beforeunload', function(event) {
var message = '변경내용을 저장하지 않았습니다.';
(event || window.event).returnValue = message;
return message;
});
<요약>
*이벤트는 브라우저가 페이지의 로딩이 끝났다거나 버튼이 클릭되었다는 등 어떤 일이 발생했음을 알리는 수단이다
*바인딩은 어떤 요소에서 어떤 이벤트가 발생했을 때, 어떻게 처리할 것인지를 정의 하는 과정이다.
*요소에서 이벤트가 발생하면 자바스크립트 함수가 호출된다. 이 함수가 웹 페이지에 어떤 식으로든 병경을 가해, 사용자의 행동에 반응을 보임으로써 인터렉티브한 느낌을 준다.
*이벤트 전파를 이용하여 특정 요소의 모든 자식 요소에서 발생한 이벤트를 모니터링 할 수 있다.
*html5 명세에 정의된 이벤트나 브라우저 종속적인 이벤트들도 있지만, 가장 비번하게 사용되는 이벤트는 w3c dom 이벤트들이다.
'매일코딩 > 자바스크립트 개념' 카테고리의 다른 글
[자바스크립트 기초]제이쿼리 2 (2) | 2017.03.03 |
---|---|
[자바스크립트 기초]제이쿼리 1 (4) | 2017.03.02 |
[자바스크립트 기초] 함수 이벤트 DOM을 이용한 초미니 프로젝트 1 (2) | 2017.02.28 |
[자바스크립트 기초 ]이벤트의 종류와 개념 1 (2) | 2017.02.26 |
[자바스크립트 기초]DOM 문서객체모델의 이해 2 (2) | 2017.02.25 |
댓글