목차
- 마우스 이벤트
1-1. 마우스 이벤트 종류
1-2. 마우스 이벤트 관련 속성
1-3. 마우스 이벤트 예시 - 키보드 이벤트
2-1. 키보드 이벤트 종류
2-2. 키보드 이벤트 관련 속성
2-3. 키보드 이벤트 예시 - 스크롤 이벤트
3-1. 스크롤 이벤트 종류
3-2. 스크롤 이벤트 관련 속성
3-3. 스크롤 이벤트 예시 - 폼 이벤트
4-1. 폼 이벤트 종류
4-2. 폼 이벤트 관련 속성
4-3. 폼 이벤트 예시
1. 마우스 이벤트
1-1. 마우스 이벤트 종류
mousedown | 요소 위에서 마우스 버튼을 누를 때 |
mouseup | 요소 위에서 마우스 버튼을 누르고 있다가 뗄 때 |
mouseover | 마우스 커서가 요소 바깥으로부터 안으로 움직일 때 |
mouseout | 마우스 커서가 요소 위에 있다가 요소 밖으로 움직일 때 |
mousemove | 마우스를 움직일 때 |
click | 마우스 버튼 사용해 동일 요소 위에서 mousedown + mouseup 이벤트를 연달아 발생시킬 때 |
dblclick | 동일 요소 위에서 마우스 왼쪽 버튼을 빠르게 클릭할 때 |
contextmenu | 마우스 오른쪽 버튼을 눌렀을 때 |
1-2. 마우스 이벤트 관련 속성
클라이언트 좌표(clientX, clientY)
event.clientX | 웹 문서를 기준으로 왼쪽에서 얼마나 떨어져 있는지 |
event.clientY | 웹 문서를 기준으로 위에서 얼마나 떨어져 있는지 |
<body>
<span id="span">마우스를 위에 올려보세요</span>
<script>
let span = document.querySelector("#span");
span.onmouseover = () => span.innerHTML = event.clientX + ":" + event.clientY;
</script>
</body>
- <span> 태그 내부문자 부분에 마우스를 올리면 해당 텍스트가 클라이언트 좌표로 대체된다.
1-3. 마우스 이벤트 예시
event.button
<body>
<button id="btn">마우스 왼쪽이나 오른쪽 버튼을 사용해 클릭</button>
<div id="area" class="area"></div>
<script>
let btn = document.querySelector('#btn');
let area = document.querySelector('#area');
btn.onmousedown = (event) => area.insertAdjacentHTML('beforeend', 'mousedown button=' + event.button + "<br>");
btn.onmouseup = (event) => area.insertAdjacentHTML('beforeend', 'mouseup button=' + event.button + "<br>");
btn.onclick = (event) => area.insertAdjacentHTML('beforeend', 'click button=' + event.button + "<br>");
btn.oncontextmenu = (event) => area.insertAdjacentHTML('beforeend', 'contextmenu button=' + event.button + "<br>");
btn.ondblclick = (event) => area.insertAdjacentHTML('beforeend', 'dblclick button=' + event.button + "<br>");
</script>
</body>
- event.button 통해 조회하자 왼쪽 버튼 0, 가운데 휠 1, 오른쪽 버튼 2라는 숫자값으로 반환되고 있다.
텍스트 선택/복사 금지
return false;
❗ 텍스트 선택 금지 : moudedown 이벤트가 발생할 때 나타나는 브라우저 기본 동작을 제한한다.
❗ 텍스트 복사 금지 : oncopy 이벤트 기본 동작을 제한한다.
<body>
<span ondblclick="alert('클릭되었습니다');" onmousedown="return false;">
이 영역은 더블 클릭해도 선택되지 않습니다
</span>
<div oncopy="alert('복사 불가능입니다!'); return false;">
..........................
</div>
</body>
- onevent에 return false; 처리해 텍스트 선택, 텍스트 복사 등 원치 않는 동작을 제한할 수 있다.
2. 키보드 이벤트
2-1. 키보드 이벤트 종류
keydown | 키를 누를 때 |
keyup | 키를 놓을 때 |
2-2. 키보드 이벤트 관련 속성
event.key | 문자 ※ 소문자 a는 a, 대문자 A는 A |
event.code | 물리적인 키 코드 ※ 소문자 a도 대문자 A도 KeyA |
2-3. 키보드 이벤트 예시
event.code=KeyA
<body>
<input type="text" id="content" placeholder="아무 키나 입력하세요">
<div id="area" class="area">
</div>
<script>
let content = document.querySelector("#content");
let area = document.querySelector("#area");
content.onkeydown = () => area1.insertAdjacentHTML('beforeend', 'keydown event.key=' + event.key + ", event.code=" + event.code + "<br>");
content.onkeyup = () => area1.insertAdjacentHTML('beforeend', 'keyup event.key=' + event.key + ", event.code=" + event.code + "<br>");
</script>
</body>
- 예시로서 Aa를 연달아 입력하거든 문자를 나타내는 event.key 속성만 다르고, 물리적 키 코드인 event.code는 동일함을 확인할 수 있다.
전화번호 입력 받기
<body>
<input type="tel" placeholder="전화번호를 입력하세요" onkeydown="return checkPhoneNumber(event.key)">
<script>
function checkPhoneNumber(key) {
return (key >= '0' && key <= '9') || key == '-' ||
key == 'ArrowLeft' || key == 'ArrowRight' ||
key == 'Delete' || key == 'Backspace';
}
</script>
</body>
- <input> 태그 통해 생성된 입력란에 '숫자'와 '대시(-)'만 받겠다고 작성하거든 백스페이스나 화살표 이동 키 또한 읽히지 않게 된다.
- 따라서 허용할 key들을 분명히 명시함이 좋다: 'ArrowLeft', 'ArrowRight', 'Delete', 'Backspace' 등
3. 스크롤 이벤트
3-1. 스크롤 이벤트 종류
scroll | 마우스의 스크롤을 움직였을 때 |
무한 스크롤 등 컨텐츠 내용 더보기 등에 활용할 수 있는 이벤트이다.
3-2. 스크롤 이벤트 관련 속성
element.scrollHeight | 요소 스크롤 뷰 높이 |
element.scrollTop | 요소 세로 스크롤 위치 |
element.scrollLeft | 요소 왼쪽 스크롤 위치 |
element.clientHeight | 요소 안쪽 높이 |
3-3. 스크롤 이벤트 예시
무한 스크롤
스크롤 끝 지점마다 이미지 반복
<head>
<style>
.area {
background : lightgray;
border : 1px solid black;
min-height: 100px;
}
.imageArea {
margin: 20px;
border: 2px solid lightgray;
height: 200px;
overflow-y: scroll;
}
</style>
</head>
- overflow-y 속성의 경우 컨텐츠가 늘어나 오버플로우가 발생하면 y축으로 스크롤을 만든다.
- 즉 위 예시에서는 지정된 높이가 height: 200px이므로, 이를 초과하면 y축 스크롤을 생성하라는 뜻에서 쓰였다: overflow-y: scroll;
<body>
<div class="imageArea"></div>
<script>
let imageArr = ['pikachu.png', 'pikachu2.png', 'pikachu3.jpg'];
let imageArea = document.querySelector(".imageArea");
let index = 0;
addImage(imageArr[index]);
function addImage(fileName) {
let html = '';
for(let i=0; i < 36; i++) {
html += "<img src='../resources/images/"+ fileName + "'width='100' height='100'>"
}
imageArea.innerHTML += html;
}
imageArea.addEventListener('scroll', function() {
console.log("imageArea 높이 : " + imageArea.clientHeight);
console.log("imageArea 스크롤 위치 : " + imageArea.scrollTop);
console.log("imageArea 스크롤 높이 : " + imageArea.scrollHeight);
if(imageArea.scrollTop + imageArea.clientHeight == imageArea.scrollHeight) {
index = ++index < imageArr.length ? index : index - imageArr.length;
addImage(imageArr[index]);
}
});
</script>
</body>
- 반복 추가할 이미지 목록을 let imageArr 변수에 담는다.
- <div> 영역을 다루기 위해 클래스명으로 선택한 뒤 마찬가지로 변수 안에 저장한다.
- 스크롤 끝 지점마다 이미지가 36장씩 순서대로 반복되는 형태를 구현할 것이므로 [0]부터 시작하는 임의의 index 변수를 선언한다.
- 함수 addImage에서는 HTML 문자열을 취급할 변수 하나를 별도로 생성한다: let html
- for문 통해 이미지 하나에 36번씩 반복이 진행된다. 동일 경로에 있는 이미지 파일들을 불러올 것이므로 인자로 받은 파일명(fileName)만 대체될 수 있는 html 문장을 작성해 누적(+=) 동작시킨다.
- 이렇게 작성 마친 변수 html을 innerHTML 통해 <div> 영역에 대입한다.
- addEventListener 통해 이벤트 핸들러를 할당한다.
- 콘솔창 출력 구문에서 clientHeight는 설정한 대로 200px 값이 고정적으로 반환된다. 반면 scrollTop 및 scrollHeight 속성은 사용자의 창 크기에 따라 정확한 수치는 다를 수 있지만, 스크롤 바를 끝까지 내렸을 때 스크롤 위치 + 요소 높이 == 스크롤 높이라는 결론을 도출할 수 있다: clientHeight(200) + scrollTop(736) == scrollHeight(936)
- 이를 토대로 조건문 if문의 조건식을 만든다.
- 또, 같은 이미지의 반복이 아니라 이미지 목록서 가지는 인덱스별 반복([0][1][2][0][1]...)을 의도하는 것이기에, ++1 증가시킨 인덱스가 이미지 목록의 길이보다 작다면 ? 인덱스 그대로 반환하고, 그렇지 않은 경우에는 (인덱스 - 이미지 목록 길이)가 수행되도록 삼항연산자 기반의 식을 세운다. ++index가 3이고, 이미지 목록 길이가 3인 상태에서 마이너스(-) 연산이 일어나 index [0]의 이미지로 돌아갈 것이다.
4. 폼 이벤트
4-1. 폼 이벤트 종류
focus | 사용자가 폼 요소를 클릭하거나 tab 키 눌러 요소로 이동했을 때 |
blur | 사용자가 다른 곳을 클릭하거나 tab 키 눌러 다음 폼 필드로 이동했을 때 |
focusin | focus와 동일하나, 버블링이 적용된다는 것이 차이점 |
focusout | blur와 동일하나, 버블링이 적용된다는 것이 차이점 |
submit | 폼 제출했을 때 |
change | 요소 변경이 끝났을 때(변경 뒤 포커스를 잃었을 때) |
input | 키보드 이벤트와 달리, 어떤 방법으로든 값 변경할 때 발생 |
cut | 값 잘라내기 할 때 |
copy | 값 복사하기 할 때 |
paste | 값 붙여넣기 할 때 |
4-2. 폼 이벤트 관련 속성
document.forms[0] : 문서 내 가장 첫 번째 <form> 반환
document.forms.memberJoin : name 속성이 memberJoin인 문서 반환
form.elements.userid : name 속성이 userid인 해당 form 안의 element 반환
document.forms | 문서에 존재하는 form들을 반환 |
form.elements | 해당 form 내의 name 속성이 일치하는 element들 반환 |
element.form | element가 속한 form 역참조 |
tabindex | 포커싱 지원하지 않는 요소도 focus 가능하게 만드는 HTML 속성 |
- 폼 요소 탐색에 쓰이는 프로퍼티는 태그 구조에 의존하지 않는다. 따라서 태그 깊이와 무관하게 form.elements 사용해 접근 가능하다.
- 반대로 모든 요소는 element.form으로 폼에 접근할 수 있다. 이를 역참조라고 부른다.
4-3. 폼 이벤트 예시
회원가입
<body>
<form name="memberJoin" method="post" action="">
<table>
<tr>
<td><label for="userid">아이디</label></td>
<td><input type="text" name="userid" id="userid" required></td>
<td><input type="button" value="중복확인"></td>
</tr>
<tr>
<td><label for="pwd1">비밀번호</label></td>
<td><input type="password" name="pwd1" id="pwd1" required></td>
<td><span id="pwdresult"></span></td>
</tr>
<tr>
<td><label for="pwd2">비밀번호확인</label></td>
<td><input type="password" name="pwd2" id="pwd2" required></td>
<td></td>
</tr>
<tr>
<td>성별</td>
<td>
<input type="radio" name="gender" id="male" value="m"><label for="male">남자</label>
<input type="radio" name="gender" id="female" value="f"><label for="female">여자</label>
</td>
<td></td>
</tr>
<tr>
<td>나이</td>
<td>
<select id="age" name="age">
<option value="10">10대 이하</option>
<option value="20">20대</option>
<option value="30">30대</option>
<option value="40">40대</option>
<option value="50">50대</option>
<option value="60">60대 이상</option>
</select>
</td>
<td></td>
</tr>
<tr>
<td>자기소개</td>
<td colspan="2"><textarea name="introduce" id="introduce" rows="5" cols="30"
style="resize:none;"></textarea></td>
</tr>
<tr>
<td><label for="email">이메일</label></td>
<td><input type="email" name="email" id="email" required></td>
<td><span id="emailresult"></span></td>
</tr>
<tr>
<td></td>
<td>
<input type="reset" value="초기화">
<input type="submit" value="회원가입">
<input type="image" value="회원가입">
</td>
<td></td>
</tr>
</table>
</form>
<script>
</body>
- 아이디, 비밀번호, 비밀번호 확인, 성별, 나이, 자기소개, 이메일 입력란을 가진 회원가입 폼을 위처럼 생성한다.
폼 얻기
document.forms
console.log(document.forms);
console.log(document.forms.memberJoin);
console.log(document.forms[0]);
- 문서 내에 존재하는 form 목록을 반환 받는다: document.forms
- 전체 조회하거든 유사 배열인 HTMLCollection 형태로 돌아오며, 이때 문서 내에 존재하는 폼이 하나뿐이라 index [0]으로서 자리한 모습이다.
- name 속성이 "memberJoin"인 form과 문서 내 순서상 첫 번째인 index [0]의 form은 결국 같은 값을 보임을 확인할 수 있다.
요소 얻기
form.elements
let form = document.forms.memberJoin;
console.log(form.elements);
console.log(form.elements.userid);
console.log(form.elements.gender);
console.log(form.elements.gender[0]);
console.log(form.elements.gender[1]);
- form을 지정할 수 있도록 변수 let form 선언해 memberJoin이라는 name을 가진 폼을 저장한다.
- form이 가진 모든 요소들에 대해 조회하자 HTMLFormControlsCollection 형태로 반환된다: form.elements
- <input type="radio">로 작성된 데 대해 요소들을 가져오면 RadioNodeList로 리턴됨을 확인할 수 있다.
- name 속성값이나 그 중에서도 해당하는 [index]를 특정해 접근 가능하다.
역참조
변수명.form
let email = form.elements.email;
console.log(email);
console.log(email.form);
- 폼을 통해 → 요소를 조회하는 것이 참조한다고 표현하고, 그 반대로 요소에서 → 폼으로 접근하는 행위를 역참조라 한다.
- 예시에서는 email이라는 변수를 생성하고, 이를 통해 변수명.form 형태로 역참조 진행한다.
폼 요소 값 다루기
input.value
사용에 있어 지양할 점이긴 하지만, 일회성 테스트 위해 id에 직접 접근한다.
<body>
<button id="test">input text</button>
<script>
document.querySelector("#test").addEventListener('click', function(){
console.log("userid.value : " + userid.value);
email.value = "email@email.com";
});
</script>
</body>
- input text 버튼 클릭 시 이메일 입력란에 지정된 value 값이 삽입된다: email.value
<body>
<button id="test">textarea</button>
<script>
document.querySelector("#test").addEventListener('click', function(){
// console.log("introduce.innerHTML : " + introduce.innerHTML);
console.log("introduce.value : " + introduce.value);
introduce.value = "아이엠그라운드~자기소개하기~";
});
</script>
</body>
- <textarea> 작성 내용을 콘솔창에 출력하고자 한다.
- 이때
introduce.innerHTML로는 출력되지 않고, introduce.value를 통해서만 가능하다.
*checkbox 또는 radio*
input.checked
<body>
<button id="test">input radio</button>
<script>
document.querySelector("#test").addEventListener('click', function(){
console.log("male.checked : " + male.checked);
female.checked = true;
});
</script>
</body>
- male.checked 구문에 있어서 라디오 버튼을 선택하지 않은 상태에서 누르면 false, 해당 값 선택하고 누르면 비로소 true가 나온다.
- 연달아 작성돼 있음에 따라 한 번 더 버튼을 클릭하면 기본값인 것처럼 female.checked가 진행된다.
*option 하위 요소를 담은 컬렉션*
select.options
*현재 선택된 option 값*
select.value
*현재 선택된 option 인덱스*
select.selectedIndex
<body>
<button id="test">select</button>
<script>
document.querySelector("#test").addEventListener('click', function(){
console.log(age.options);
age.options[2].selected = true;
age.selectedIndex = 3;
age.value = '50';
console.log("age.options[2].selected : " + age.options[2].selected); //false
console.log("age.selectedIndex : " + age.selectedIndex); //4
console.log("age.value : " + age.value); //50
});
</script>
</body>
생성된 <select>~<option> 결과는 위와 같다.
- .options를 물으면 하위 요소를 담은 HTMLOptionsCollection 형태로 반환된다.
- index [2]에 대고 .selected 한 것이 true임을 작성하거든 해당되는 30대로 값이 들어간다: age.options[2].selected = true;
- 혹은 .selectedIndex로 지정할 수도 있다. 이때는 40대가 선택된다: age.selectedIndex = 3;
- 설정된 option의 .value 값을 활용해 접근할 수도 있다. 작성 순서에 따라 50대가 최종 반영된다: age.value = '50';
- 이를 토대로 콘솔창에 정보를 출력하려 하거든 현재 값은 50대이므로 index [2]가 선택되었는지 묻는 데는 false 값이 리턴될 것이다.
- 선택된 인덱스를 묻는 질문에는 [4], 밸류 값은 50으로 돌아옴을 알 수 있다.
focus/blur 이벤트
❗ focus는 사용자가 폼 요소를 클릭하거나 탭(tab) 키 눌러 요소로 이동했을 때 시행된다. autofocus라는 HTML 속성을 통해서도 포커스할 수 있으며, 이는 페이지가 로드된 후 자동으로 포커싱되는 것을 일컫는다. blur는 사용자가 다른 곳을 클릭하거나 탭(tab) 키 눌러 다음 폼 필드로 이동했을 때 포커싱 해제되는 것을 말한다. focus/blur 메소드로 요소에 포커스를 부여하거나 제거할 수가 있다.
<head>
<style>
.invalid {
border-color : red;
}
[id$=result] { /* result로 끝나는 영역 */
color : red;
}
.focused {
outline : 3px dotted lightgray;
}
</style>
</head>
<body>
<button id="testA">userid focus</button>
<button id="testB">userid blur</button>
<script>
testA.addEventListener('click', () => userid.focus());
testB.addEventListener('click', () => userid.blur()); //focus 제거
email.onblur = function(){
if(!this.value.includes('@')) {
emailresult.innerHTML = '올바른 이메일 주소를 입력하세요';
this.classList.add('invalid');
}
};
email.onfocus = function() { //다시 포커스하면 빨간줄, 빨간글씨 제거
if(this.classList.contains('invalid')){
this.classList.remove('invalid');
emailresult.innerHTML = '';
}
}
</script>
</body>
- 이메일 입력란에 골뱅이(@, 앳) 표시가 들어있는지 여부를 확인해 안내 문구를 출력한다.
focusin/focusout 이벤트
❗ focusin/focusout은 앞서 다룬 focus와 유사하지만, 버블링이 적용된다는 특징이 있다.
<body>
<script>
// 1. 폼 안에 포커스가 된 경우 클래스 추가해보기(X)
// focus 이벤트는 버블링되지 않음 -- 그냥 focus는 버블링되지 않는다!!!!!!!!
// form.onfocus = () => form.className = 'focused'; //전역변수 form. onfocus라고 작성한 것임
// 2. focusin과 focusout 사용 시 이벤트 버블링 적용됨
form.addEventListener('focusin', () => form.classList.add('focused'));
form.addEventListener('focusout', () => form.classList.remove('focused'));
</script>
</body>
change 이벤트
❗ change는 요소 변경이 끝나면 발생한다. 즉 텍스트 입력 요소인 경우요소 변경이 끝날 때가 아니라 포커스를 잃었을 때 이벤트가 시행된다. select/checkbox/radio는 선택값이 변경된 직후 실시된다.
<body>
<script>
form.introduce.addEventListener('change', () => alert('introduce changed!'));
form.age.addEventListener('change', () => alert('age changed!'));
</script>
</body>
input 이벤트
❗ input은키보드 이벤트와 달리어떤 방법으로든 값을 변경할 때 발생한다. 예를 들면 마우스를 사용해 글자를 붙여넣거나, 음성 인식 기능을 통해 글자를 입력할 때도 반응한다.
<body>
<script>
pwd1.addEventListener('input', function(){
if(pwd1.value != pwd2.value) {
pwd1.classList.add('invalid');
pwd2.classList.add('invalid');
pwdresult.innerHTML = '비밀번호가 일치하지 않습니다';
} else {
pwd1.classList.remove('invalid');
pwd2.classList.remove('invalid');
pwdresult.innerHTML = '';
}
});
pwd2.addEventListener('input', function(){
if(pwd1.value != pwd2.value) {
pwd1.classList.add('invalid');
pwd2.classList.add('invalid');
pwdresult.innerHTML = '비밀번호가 일치하지 않습니다';
} else {
pwd1.classList.remove('invalid');
pwd2.classList.remove('invalid');
pwdresult.innerHTML = '';
}
});
</script>
</body>
- 비밀번호, 비밀번호 확인을 입력하는 동안 확인이 치러진다.
- pwd1, pwd2 둘 다 동일한 함수가 들어가므로 실사용 시에는 별도 함수와 변수를 정의해 사용하는 것이 좋겠다. id, name 속성값에 직접 접근하는 것은 오류 발생 가능성에 대비하여 삼가야 하기 때문이다.
submit 이벤트
❗ submit은 폼을 제출할 때 발생한다. 폼을 서버로 전송하기 전 내용 검증하여 전달 과정을 취소할 때 쓰인다. 폼을 전송하는 방법으로는 다음과 같은 방법이 있다: ① input type="submit" 또는 input type="image" ② input 필드에서 Enter 키 누르기
❗ form.submit() 메소드는 자바스크립트만으로 폼 전송을 실시하고자 할 때 사용된다. 동적으로 폼을 생성하고 서버에까지 내보내기가 가능하다. 단,이때는 submit 이벤트가 생성되지는 않는다.
<body>
<button id="search">네이버 검색하기</button>
<script>
search.addEventListener('click', function(){
let keyword = prompt('검색어를 입력해 주세요');
if(keyword) {
let newForm = document.createElement('form');
newForm.action = 'https://search.naver.com/search.naver';
newForm.method = 'GET';
newForm.innerHTML = '<input type="text" name="query" value="' + keyword + '">';
document.body.append(newForm);
newForm.submit();
} else {
alert('검색어를 입력하지 않으셨습니다');
}
});
</script>
</body>
- 폼 제출을 위해서는 해당 폼이 문서 내에 존재해야 한다.
- 예시에서는 <body> 밑에 생성한 <form> 태그가 삽입되도록 썼다: document.body.append(newForm);
'Frontend > JavaScript' 카테고리의 다른 글
[JavaScript] DOM 이벤트 | 이벤트 핸들러 | addEventListener | 버블링 (0) | 2022.02.23 |
---|---|
[JavaScript] BOM | window | setInterval | 타이머 메소드 (0) | 2022.02.22 |
[JavaScript] 문서 수정 | 노드 메소드 | insertAdjacentHTML | classList (0) | 2022.02.22 |
[JavaScript] 주요 노드 프로퍼티 | innerHTML | textContent | value (0) | 2022.02.21 |
[JavaScript] 요소 검색 메소드 | querySelector | NodeList (0) | 2022.02.21 |