<button type="button" onClidk="sayHi('Lee')">Click me!</button>
<script>
function sayHi(name) {
console.log(`Hi! ${name}.`);
}
// onclick 함수는 암묵적으로 아래의 코드처럼 생성이 됨.
function onclick(name) {
sayHi(name);
}
</script>
<button type="button">Click me!</button>
<script>
const $button = document.querySelector('button');
// 이벤트 핸들러 프로퍼티에 이벤트 핸들러 바이딩
$button.onclick = function() {
console.log('button click');
};
// 두번째로 바인딩된 이벤트 핸들러가 덮어쓰기 됨
$button.onclick = function() {
console.log('button click2!!');
};
</script>
EventTaget.prototype.addEventListener 메서드를 사용하여 이벤트 핸들러를 등록할 수 있다.
addEventListener 메서드에는 이벤트 핸들러를 인수로 전달하여 바인딩 한다.
만약, 이벤트 핸들러 프로퍼티 방식과 addEventListener 방식 모두 사용하면 2개의 이벤트 핸들러가 모두 호출 된다.
addEventListener 메서드는 하나 이상의 이벤트 핸들러를 등록할 수 있다. 이때 이벤트 핸들러는 등록한 순서대로 호출된다.
만약 참조가 동일한 이벤트 핸들러를 중복 등록하면 하나의 이벤트 핸들러만 등록된다.
EventTaget.addEventListener('eventType', functionName [, useCapture]);
EventTaget : 이벤트 타깃
eventType : 이벤트 타입
functionName : 이벤트 핸들러
useCapture : capture 사용 여부
<button type="button">Click me!</button>
<script>
const $button = document.querySelector('button');
// 첫번째 이벤트 핸들러가 먼저 실행되고
$button.addEventListener('click', function() {
console.log('button click[1]');
})
// 그 다음에 두번째 이벤트 핸들러가 실행 된다.
$button.addEventListener('click', function() {
console.log('button click[2]');
})
// 동일한 참조의 이벤트 핸들러 중복 등록
const handleClick = () => console.log('button click! [3]');
// 하나만 등록됨.
$button.addEventListener('click', handleClick);
$button.addEventListener('click', handleClick);
</script>
<button type="button">Click me!</button>
<script>
const $button = document.querySelector('button');
const handleClick = () => console.log('button click! [3]');
// 이벤트 핸들러 등록
$button.addEventListener('click', handleClick);
$button.removeEventLister('click', handleClick, true); // 실패
$button.removeEventLister('click', handleClick); // 성공
// 기명 함수를 이벤트 핸들러로 등록
$button.addEventListener('click', function foo() {
console.log('button click');
$button.removeEventListener('click', foo);
})
// 이벤트 핸들러 프로퍼티 방식의 경우
$button.onclick = handleClick;
$button.onclick = null;
</script>
const $msg = document.querySelector('.msg');
// 클릭 이벤트에 의해 생성된 이벤트 객체는 이벤트 핸들러의 첫번째 인수로 전달된다.
function showCoords(e) {
$msg.textContent = `clientX: ${e.clientX}, clientY: ${e.clientY}`;
}
document.onclick = showCoords;
// 이벤트 핸들러 어트리뷰트의 경우
<body onclick="showCoords(event)"></body>
공통 프로퍼티
DOM 요소를 드래그하여 이동시키는 예제
<!-- css -->
<style>
.box {width: 100px; height: 100px; background: orange, border: 5px solid red; cursor: pointer;}
</style>
<!-- html -->
<div class="box"></div>
<!-- js -->
<script>
const $box = document.querySelector('.box');
// 드래그 시작 시점의 마우스 포인터 위치
const initailMousePos = { x: 0, y : 0 };
// 오프셋 : 이동할 거리
const offset = { x : 0, y : 0 };
// mousemove 이벤트 핸들러
const move = e => {
// 오프셋 = 현재(드래그하고 있는 시점) 마우스 포인터 좌표 - 드래그 시작 시점의 마우스 포인터 좌표
offset.x = e.clientX - initailMousePos.x;
offset.y = e.clientY - initailMousePos.y;
// translate3d는 GPU를 사용하므로 absolute의 top, left를 사용하는 것보다 빠르다.
//top, left는 레이아웃에 영향을 준다.
$box.style.transform = `translate3d(${offset.x}px, ${offset.y}px, 0)`;
};
// mousedown 이벤트가 발생하면 드래그 시작 시점의 마우스 포인터 좌표를 저장한다.
$box.addEventListener('mousedown', e => {
// 한 번 이상 드래그로 이동한 경우 move에서 translate3d로 이동한 상태이므로 offset.x 와 offset.y를 빼주어야 한다.
initailMousePos.x = e.clientX - offset.x;
initailMousePos.y = e.clientY - offset.y;
// mousedown 이벤트가 발생한 상태에서 mosemove 이벤트가 발생하면 box요소를 이동시킨다.
document.addEventListener('mousemove', move);
});
// mouseup 이벤트가 발생하면 mousemove 이벤트를 제거해 이동을 멈춘다.
document.addEventListener('mouseup', () => {
document.removeEventListener('mousemove', move);
})
</script>
input 요소의 입력 필드에 엔터 키가 입력되면 현재까지 입력 필드에 입력된 값을 출력하는 예제
<!-- html -->
<input type="text" />
<em class="message"></em>
<!-- js -->
<script>
const $input = document.querySelector('input[type=text]');
const $msg = document.querySelector('.message');
$input.onkeyup = e => {
// e.key는 입력한 키 값을 문자열로 반환한다.
if(e.key !== 'Enter') return;
// 엔터키가 입력되면 현재까지 입력 필드에 입력된 값 출력
$msg.textContent = e.target.value;
e.target.value = '';
};
</script>
function active({target}) {
// 이벤트를 발생시킨 요소가 ul#fruits의 자식 요소가 아니라면 무시한다
if (!target.matches('#fruits > li')) return;
}
document.querySelector('a').onclick = e => {
// a 요소의 기본 동작 중단
e.preventDefault();
}
document.querySelector('input[type=checkbox]').onclick = e => {
// checkbox 요소의 기본 동작 중단
e.preventDefault();
}
// 이벤트 위임. 클릭된 하위 버튼 요소의 color 변경
document.querySelector('.container').onclick = ({target}) => {
if(!target.matchecs('.container > button')) return;
target.style.color = 'red';
};
// .btn2 요소는 이벤트를 전파하지 않으므로 상위 요소에서 이벤트를 캐치할 수 없다
document.querySelector('.btn2').onclick = e => {
e.stopPropagation(); // 이벤트 전파 중단
e.target.style.color = 'blue';
};
<button onclick="handleClick(this)">Click me!</button>
<script>
function handleClick(button) {
console.log(button); // 이벤트를 바인딩한 button 요소
console.log(this); // window
}
</script>
<button type="button" class="btn1">0</button>
<button type="button" class="btn2">0</button>
<script>
const $button1 = document.querySelector('.btn1');
const $button2 = document.querySelector('.btn2');
// 이벤트 핸들러 프로퍼티 방식
$button1.onclick = function(e){
console.log(this); // $button1
console.log(e.currentTarget); // $button1
};
// addEventListener 방식
$button2.addEventListener('click', function(e){
console.log(this); // $button2
console.log(e.currentTarget); // $button2
});
// 이벤트 핸들러 프로퍼티 + 화살표 함수 방식
$button1.onclick = (e) => {
console.log(this); // window
console.log(e.currentTarget); // $button1
};
// addEventListener + 화살표 함수 방식
$button1.addEventListener('click', e => {
console.log(this); // window
console.log(e.currentTarget); // $button2
});
</script>
<button type="button" class="btn">0</button>
<script>
class App {
constructor() {
this.$button = document.querySelector('.btn');
this.count = 0;
// 이벤트 핸들러 프로퍼티 방식(클래스 필드에 일반 함수 등록)
this.$button.onclick = this.increase1.bind(this);
// 이벤트 핸들러 프로퍼티 방식(클래스 필드에 화살표 함수 등록)
this.$button.onclick = this.increase2;
}
increase1() {
this.$button.textContetn = ++this.count;
}
increase2 = () => this.$button.textContent = ++this.count;
}
</script>
<input type="text">
<em class="message"></em>
<script>
const MIN_USER_NAME_LENGTH = 5;
const $input = document.querySelector('input[type="text"]');
const $msg = document.querySelector('.message');
// 1. 이벤트 핸들러 내부에서 함수를 호출하면서 인수를 전하는 방법
const checkUserNameLength = min => {
$msg.textContetn = $input.value.length < min ? `이름을 ${min}자 이상 입력해주세요.` : '';
};
$input.onblur = () => {
checkUserNameLength(MIN_USER_NAME_LENGTH);
}
// 2. 이벤트 핸들러를 반환하는 함수를 호출하면서 인수를 전달하는 방법
const checkUserNameLength = min => e => {
$msg.textContetn = $input.value.length < min ? `이름을 ${min}자 이상 입력해주세요.` : '';
};
$input.onblur = checkUserNameLength(MIN_USER_NAME_LENGTH);
</script>
const keyboardEvent = new KeyboardEvent('keyup');
console.log(keyboardEvent.type); // keyup
const customEvent = new CustomEvent('foo');
console.log(customEvent.type); // foo
console.log(customEvent.bubbles); // false
console.log(customEvent.cancelable); // false
const customEvent2 = new CustomEvent('bar', {
bubbles: true,
cancelable: true,
});
console.log(customEvent2.type); // foo
console.log(customEvent2.bubbles); // true
console.log(customEvent2.cancelable); // true
console.log(customEvent2.isTrusted); // false
const mouseEvent = new MouseEvent('click', {
bubbles: true,
cancelable: true,
clientX: 50,
clientY: 100
});
console.log(mouseEvent.clientX); // 50
console.log(mouseEvent.clientY); // 100
<button type="button" class="btn">0</button>
<script>
const $button = document.querySelector('.btn');
// 버튼 요소에 foo 커스텀 이벤트 핸들러 등록
// 커스텀 이벤트를 디스패치하기 이전에 이벤트 핸드러를 등록해야 한다.
$button.addEventListener('foo', e => {
alert(e.detail.message);
});
// CustomEvent 생성자 함수로 foo 이벤트 타입의 커스텀 이벤트 객체를 생성
const customEvent = new CustomEvent('foo', {
detail: { message: 'Hello' } // 이벤트와 함께 전달하고 싶은 정보
});
// 커스텀 이벤트 디스패치(커스텀 이벤트 실행)
$button.dispatchEvent(customEvent);
</script>