JavaScript의 이벤트에 대해 알아보자
이벤트(event)
✔️ 이벤트 관련 용어
1. event target : 이벤트를 당하는 요소 객체
2. event type : 이벤트 종류
3. event handler : 해당 이벤트가 발생했을 때 동작하는 코드
1. 이벤트 모델 종류
👉🏻 고전 이벤트 모델 (== 기본 이벤트 모델)
👉🏻 인라인 이벤트 모델 (우리가 그동안 자주 사용한 방식 - button 태그에 onclick 바로 설정)
👉🏻 표준 이벤트 모델 (표준을 지키지 않는 브라우저에서는 동작 안 함)
*고전 이벤트 모델 (기본 이벤트 모델)
👉🏻 요소 객체를 코드상으로 끌고 와서 해당 요소 객체의 이벤트 속성에 접근한 후
이벤트 핸들러를 연결하는 방식
이벤트를 추가할 수도 있지만 이벤트를 제거할 수도 있음 (null을 대입)
👉🏻 요소 내부에 직접적으로 이벤트 속성 기술 X
<!-- button[id=btn$]{실행확인}*2 + Enter -->
<button id="btn1">실행확인</button>
<button id="btn2">실행확인</button>
<div id="area1" class="area"></div>
<script>
var area1 = document.getElementById("area1");
// 각각의 버튼 요소 객체에 고전 이벤트 모델 방식으로 이벤트 부여
/*
var btn1 = document.getElementById("btn1");
btn1.onclick = function() { // 이벤트 핸들러 함수 (익명함수)
area1.innerHTML += "btn1이 클릭되었습니다. <br>"
}
*/
// 이렇게 코드 한 줄로 줄일 수도 있음
document.getElementById("btn1").onclick = function() {
area1.innerHTML += "btn1이 클릭되었습니다. <br>"
}
</script>
<button id="btn1">실행확인</button>
<button id="btn2">실행확인</button>
<div id="area1" class="area"></div>
<script>
var area1 = document.getElementById("area1");
// 각각의 버튼 요소 객체에 고전 이벤트 모델 방식으로 이벤트 부여
/*
var btn1 = document.getElementById("btn1");
btn1.onclick = function() { // 이벤트 핸들러 함수 (익명함수)
}
*/
// 이렇게 코드 한 줄로 줄일 수도 있음
document.getElementById("btn1").onclick = function() {
area1.innerHTML += "btn1이 클릭되었습니다. <br>"
}
document.getElementById("btn2").onclick = function() {
area1.innerHTML += "btn2가 클릭되었습니다. btn1의 이벤트도 제거함 <br>";
document.getElementById("btn1").onclick = null; // 이벤트 제거
// 이벤트가 제거된 후 btn1을 다시 클릭하면 아무것도 실행되지 않음
}
</script>
👉🏻 두 번째 실행확인 버튼(btn2)을 누른 후에는 첫 번째 실행확인 버튼(btn1)을 눌러도 출력문 안 나옴
*인라인 이벤트 모델
👉🏻 그동안 우리가 가장 많이 사용했던 방식
👉🏻 요소 내부에 직접적으로 이벤트 속성을 제시해서 실행할 내용을 정의하는 방식
주로 script 태그 내에 정의되어 있는 선언적 함수를 호출하는 방식 더 선호
👉🏻 이벤트 속성값으로 직접 코드를 기술하는 방식
요소 내부에 직접적으로 이벤트를 기술, 실행은 잘되지만 한 줄의 내용이 복잡하고 길어지기 때문에 잘 쓰지는 않는 방식
<button onclick="document.getElementById('area2').innerHTML += '첫 번째 버튼 클릭 <br>'";>실행확인</button>
<!-- 선언적 함수를 만들고 이벤트 속성값으로 그 선언적 함수를 호출하는 방식 -->
<button onclick="test1();">실행확인</button>
<div id="area2" class="area"></div>
<script>
function test1() {
document.getElementById("area2").innerHTML += "두 번째 버튼 클릭 <br>";
}
</script>
*표준 이벤트 모델(addEventListener라는 함수를 이용한 방식)
👉🏻 요소 객체를 코드상으로 끌고 와서 해당 요소 객체에 addEventListener라는 메소드를 통해 이벤트를 부여하는 방식
웹에서 이벤트를 부여하는 표준 방식으로 알려져 있음 (IE 9 버전 밑으로는 적용 안 됨)
👉🏻 요소 내부에 직접적으로 이벤트 속성 기술 X
✔️ 이벤트를걸고자하는요소객체.addEventListener("이벤트명", 이벤트핸들러함수);
✔️ 버튼 안으로 마우스 포인터가 들어가는 순간 발생하는 이벤트: mouseenter
✔️ 버튼 밖으로 마우스 포인터가 나가는 순간 발생하는 이벤트: mouseout
✔️ 이벤트를걸고자하는요소객체.addEventListener("이벤트명", 이벤트핸들러함수);
<button id="btn3">실행확인</button>
<script>
var btn3 = document.getElementById("btn3");
btn3.addEventListener("click", function() {
alert("표준이벤트모델 테스트");
});
</script>
✔️ 버튼 안으로 마우스 포인터가 들어가는 순간 발생하는 이벤트: mouseenter
<button id="btn3">실행확인</button>
<script>
var btn3 = document.getElementById("btn3");
btn3.addEventListener("click", function() {
alert("표준이벤트모델 테스트");
});
btn3.addEventListener("mouseenter", function() {
btn3.style.backgroundColor = "red";
});
</script>
마우스를 한 번 올렸던 이상 계속 이벤트 유지됨
한 번 들어가고 난 이상(이벤트 발생 후) 다시 돌아오지 않음
즉, hover랑은 다름: 마우스가 들어가고 나가는 게 한 세트
자바스크립트에서는 hover라는 이벤트를 제공하지 않음
hover를 구현하고 싶을 경우: mouseenter + mouseout
✔️ 버튼 밖으로 마우스 포인터가 나가는 순간 발생하는 이벤트: mouseout
<button id="btn3">실행확인</button>
<script>
var btn3 = document.getElementById("btn3");
btn3.addEventListener("click", function() {
alert("표준이벤트모델 테스트");
});
btn3.addEventListener("mouseenter", function() {
btn3.style.backgroundColor = "red";
});
btn3.addEventListener("mouseout", function(){
btn3.style.backgroundColor = "yellow";
});
</script>
2. 현재 이벤트가 발생한 해당 요소 객체에 접근하는 방법
1. 고전 이벤트 모델 방식에서 target에 접근하는 방법
<button id="btn4">고전 이벤트 방식</button>
<button id="btn5">표준 이벤트 방식</button>
<button>인라인 이벤트 방식</button>
<script>
// 1. 고전 이벤트 모델 방식에서 target에 접근하는 방법
document.getElementById("btn4").onclick = function(e) { // 이벤트 핸들러
// 항상 window 객체는 event라는 속성을 가지고 잇음
// => 현재 이 브라우저에서 일어난 이벤트 정보를 가지고 있음
console.log(window.event); // PointerEvent 또는 MouseEvent 객체
// 마우스를 사용할 때 발생하는 이벤트
// 이벤트 발생 시 내부적으로 마치 매개변수처럼 알게 모르게 전달됨
// 직접적으로 타고 들어감
console.log(e); // PointerEvent 또는 MouseEvent 객체
// 이벤트 발생 시 매개변수 e로 전달
// 알게 모르게 전달된 이벤트를 당한 애를 꺼내 옴
// 즉, 둘의 결과는 똑같음
// this: 현재 이벤트를 당한 요소
// window.event == e
// 위의 이벤트 정보들에는 각각 target이라는 속성이 존재 => 이벤트를 당한 요소 객체
// 이벤트를 당한 target에 접근하려면
// window.event.target == e.target == this
// 위의 세 가지 방법 중 하나를 쓰면 됨
console.log(window.event.target);
console.log(e.target);
console.log(this); // id 속성값이 "btn4"인 요소 객체
window.event.target.style.backgroundColor = "red";
e.target.innerHTML = "버튼클릭됨";
this.style.color = "white";
alert(this.id);
};
</script>
2. 표준 이벤트 모델 방식에서 target을 얻는 방법
<script>
// 2. 표준 이벤트 모델 방식에서 target을 얻는 방법
document.getElementById("btn5").addEventListener("click", function(e) {
console.log(window.event.target);
console.log(e.target); // 고전 이벤트 방식과 마찬가지로 매개변수 e를 전달 (익명함수이기 때문)
console.log(this);
// 셋 다 같은 결과
alert(e.target.innerHTML + " 버튼이 클릭됨");
});
</script>
3. 인라인 이벤트 모델 방식에서 target을 얻는 방법
<script>
// 3. 인라인 이벤트 모델 방식에서 target을 얻는 방법
function test2(e) { // 엄밀히 말하면 이 선언적 함수는 어디서든지 호출이 가능하기 때문에(= 이벤트가 일어나지 않아도 호출 가능)
// 이벤트 핸들러라고 취급할 수는 없음!
console.log(window.event.target);
// <button onclick="test2();">인라인 이벤트 방식</button>
// console.log(e); // undefined (자료형 지정 안 됨, 값 없음)
// console.log(e.target); // 오류 발생
// => test2 함수를 호출할 때 매개변수를 같이 넣지 않았기 때문에 사용 불가
// => 인라인 방식은 태그 내에서 선언적 함수를 직접 호출하는 방식이기 때문에
// e 라는 매개변수를 이용하여 접근하는 방식이 불가능
console.log(this); // window 객체가 출력
// Window {window: Window, self: Window, document: document, name: '', location: Location, …}
// => 선언적 함수에서 this를 쓰면 window 객체를 가리킨다
// => 전역변수 또한 window 객체의 필드로 잡혔었음! (같은 맥락)
// 위의 두 방식은 해당요소객체(버튼).이벤트호출 이라는 구조였기 때문에
// this로 버튼을 불러올 수 있었지만
// 일반 선언적 함수를 이용하여 호출하는 인라인 이벤트 모델 방식일 경우에는
// window.event.target만 가능
console.log(this.event.target); // 이 경우 window == this 이기 때문에 이 표현은 가능
// <button onclick="test2();">인라인 이벤트 방식</button>
}
</script>
*인라인 이벤트 방식은 this를 이용하면 window가 나오지만
아예 버튼 클릭 시 현재 이벤트가 발생한 요소 자체를 전달할 수는 있음 => 전달값으로 this 넘기기
<button onclick="test3(this);">인라인 이벤트 방식2</button>
<!-- 여기서의 this는 button임 -->
<script>
// 호출 시 현재 이벤트가 발생한 요소를 this 매개변수로 전달한 경우
function test3(el) {
console.log(el)
}
</script>
*총 정리
- 고전 이벤트 모델, 표준 이벤트 모델: window.event.target, e.target, this
(익명함수를 이용한 방식이라 가능)
- 인라인 이벤트 모델: window.event.target
(선언적 함수를 이용한 방식이라 한 가지만 가능)
*익명 함수
👉🏻 특정 변수나 속성에 "대입"되는 함수 제시 시 주로 사용됨
(주로 이벤트 핸들러 작성 시 사용)
*선언적 함수
[ 표현법 ]
function 함수명(매개변수명, 매개변수명) {
해당 함수 호출 시 실행할 소스코드들;
return 결과값
};
👉🏻 반환할 결과값이 없는 경우 return 구문 생략 가능
👉🏻 매개변수가 없는 경우 매개변수명들 생략 가능
3. 태그별 기본적으로 가지고 있는 이벤트를 제거
👉🏻 기본적으로 이벤트를 가지고 있는 요소
- a 태그: 클릭 시 href에 제시되어 있는 url을 요청하는 기본 이벤트를 보유
- form 태그 내의 submit 버튼 : 클릭 시 사용자가 입력한 정보들을 action 속성에 제시되어 있는 url로 제출하면서 요청하는 기본 이벤트
👉🏻 태그 내에 기본적으로 설정되어 있는 이벤트를 제거하고자 한다면? (실행 안 되게끔 막고 싶다면)
✔️ 이벤트 핸들러의 return 값을 false로 설정하면 됨 (제거)
✔️ 기본 이벤트가 있는 요소에 onclick 속성을 부여하면 (click 이벤트를 추가하면) onclick이 우선적으로 먼저 실행됨
=> 기본 이벤트가 수행되지 않게 하려면 return false;를 적어 주면 됨
✔️ event.preventDefault();
👉🏻 얘도 사용 가능!
👉🏻 return false;는 return 구문 이후의 코드가 실행되지 않지만 이 이벤트를 사용할 시에는 어느 코드 사이에 쓰더라도 로직에 영향을 주지 않고 기본 이벤트만 제거할(막을) 수 있음
<a href="http://www.naver.com" onclick="alert('살짝졸려요 Zzz'); return false;">네이버로 이동</a>
<br>
<a href="http://www.naver.com" onclick="return test4();">네이버로 이동</a>
<!--
<a href="http://www.naver.com" onclick="test4(); return false;">네이버로 이동</a>
이 코드를 써도 됨! 하지만 이렇게 될 경우에는 무조건 기본 이벤트를 제거하겠다는 의미
-->
<!-- return false; 라는 구문이 최종적으로 onclick 속성에 존재해야지만 기본 이벤트가 제거됨 -->
<script>
function test4() {
alert("ㅋㅋㅋㅋㅋ응 그래도 갈 거야");
return false; // 이 경우에는 기본 이벤트 제거가 되지 않음
}
</script>
<정리>
<a href="http://www.naver.com" onclick="test4();">네이버로 이동</a>
<!-- 결국 false;만 남은 꼴이기 때문에 기본 이벤트가 제거되지 않음 -->
<a href="http://www.naver.com" onclick="return test4();">네이버로 이동</a>
<!-- return false;가 남은 꼴이기 때문에 기본 이벤트가 제거됨 -->
기본 이벤트 제거 대표 예시 - form & submit
회원가입
- 유효성 검사 시 if문으로 각각의 조건을 주게 되면 식이 너무 길어지고 복잡해짐
👉🏻 정규 표현식을 통해 더욱 간단하게 표현 가능
✔️ 1단계: // => 정규 표현식 틀
✔️ 2단계: /^$/ => ^(시작부터) $(끝까지) 검사를 할 건데
✔️ 3단계: /^[]$/ => [] 내의 문자 중 하나라도 존재할 경우
✔️ 4단계: /^[a-z]$/ => a부터 z까지
✔️ 5단계: /^[a-zA-Z]$/ => 그리고 A부터 Z까지
✔️ 6단계: /^[a-zA-Z0-9]$/ => 그리고 0부터 9까지도
✔️ 7단계: /^[a-zA-Z0-9]{5,12}$/ => 5글자 이상 12글자 이하인지 글자 수 체크
✔️ 패턴에 맞는지 검사
if(!regExp.test(userId)) {
👉🏻 정규 표현식 객체에서 제공하는 test 함수로 패턴이 맞다면 true, 아니라면 false를 반환
alert("유효한 아이디가 아닙니다! 다시 입력해 주세요!");
👉🏻 사용자에게 다시 입력을 유도
document.getElementById("userId").select();
return false;
}
<form action="test.do" method="post">
아이디: <input type="text" name="userId" id="userId"> <br>
<label>영문자 또는 숫자로만 총 5~12자 사이로 입력해 주세요.</label> <br><br>
비밀번호 : <input type="password" name="userPwd" id="userPwd"> <br><br>
비밀번호 확인: <input type="password" id="checkPwd"> <br><br>
<input type="submit" value="회원가입" onclick="return validate();">
<!-- validate(): 유효성을 검사해 주는 함수로 쓸 이름 -->
</form>
<script>
// 유효성 검사 함수
function validate() {
// 입력한 값이 모두 유효한 경우 true 반환
// 하나라도 유효하지 않은 경우 false 반환
// 사용자가 입력한 값들
var userId = document.getElementById("userId").value;
var userPwd = document.getElementById("userPwd").value;
var checkPwd = document.getElementById("checkPwd").value;
// 2. 아이디에 대한 유효성 검사
// 영문자 또는 숫자로만 총 5~12자 사이로 입력해 주세요.
// => 이 조건에 맞는지 검사
// => 이 조건에 맞지 않을 경우 => submit의 기본 이벤트 제거
/*
if(userId.length >= 5 && userId.length <= 12) {
// 각 자리의 문자들이 영문자 또는 숫자로만 이루어져 있는지 다 검사
for(var i = 0; i < userId.length; i++) {
if(userId.charAt(i) >= 0 && userId.charAt(i)) <= 9
|| userId.charAt(i) >= 'a' && userId.charAt(i)) <= 'z'
|| userId.charAt(i) >= 'A' && userId.charAt(i)) <= 'Z') {
}
}
} else {
return false;
}
// 너무 복잡하고 식이 길어서 이렇게 안 쓸 거임!
*/
// 정규 표현식을 통해서 유효한 아이디에 해당되는 특정 패턴을 만들어 보자
var regExp = /^[a-zA-Z0-9]{5,12}$/; // regular expression : 정규 표현식 객체
// // 로 가둬서 패턴을 만듦
// 1단계: // => 정규 표현식 틀
// 2단계: /^$/ => ^(시작부터) $(끝까지) 검사를 할 건데
// 3단계: /^[]$/ => [] 내의 문자 중 하나라도 존재할 경우
// 4단계: /^[a-z]$/ => a부터 z까지
// 5단계: /^[a-zA-Z]$/ => 그리고 A부터 Z까지
// 6단계: /^[a-zA-Z0-9]$/ => 그리고 0부터 9까지도
// 7단계: /^[a-zA-Z0-9]{5,12}$/ => 5글자 이상 12글자 이하인지 글자 수 체크
// 패턴에 맞는지 검사
if(!regExp.test(userId)) { // 정규 표현식 객체에서 제공하는 test 함수
// 패턴이 맞다면 true, 아니라면 false를 반환
alert("유효한 아이디가 아닙니다! 다시 입력해 주세요!");
// 사용자에게 다시 입력을 유도
document.getElementById("userId").select();
return false;
}
// 1. 비밀번호에 대한 유효성 검사
// 비밀번호와 확인비밀번호가 일치하는지 검사
// 일치하지 않는 경우 => submit의 기본 이벤트 제거
if(userPwd != checkPwd) {
alert("비밀번호가 일치하지 않습니다.");
return false;
}
}
</script>