Event Listener
Short book about the event listener
1. Mouse Event π©βπ»
1. Click
<div class="parent">
<div class="child"></div>
</div>
.parent {
width: 300px;
height: 200px;
padding: 20px;
border: 10px solid;
background-color: red;
overflow: auto;
}
.child {
width: 200px;
height: 100px;
border: 10px solid;
background-color: orange;
}
const childEl = document.querySelector('.child');
childEl.addEventListener('click', (event) => {
console.log(`Alt(Option): ${event.altKey}`);
console.log(`Ctrl(Control): ${event.ctrlKey}`);
});
Alt(Option)
ν€ λλ Ctrl(Control)
ν€λ₯Ό ν¨κ» λλ λμ§ μ μ μλ€.
2. Double Click
.child.active {
background-color: yellowgreen;
}
const childEl = document.querySelector('.child');
childEl.addEventListener('dblclick', () => {
childEl.classList.toggle('active');
});
3. Mouse Down & Mouse Up
const childEl = document.querySelector('.child');
childEl.addEventListener('mousedown', () => {
childEl.classList.add('active');
});
childEl.addEventListener('mouseup', () => {
childEl.classList.remove('active');
});
mousedown
μ΄λ²€νΈμ mouseup
μ΄λ²€νΈλ₯Ό λλ λ±λ‘νλ©΄ λ§μ°μ€λ₯Ό ν΄λ¦μ€μΌ λμ ν΄λ¦μμ μμ λ λλ₯Ό λλ μ²λ¦¬ν μ μλ€.
4. Mouse Enter & Mouse Leave
const childEl = document.querySelector('.child');
childEl.addEventListener('mouseenter', () => {
childEl.classList.add('active');
});
childEl.addEventListener('mouseleave', () => {
childEl.classList.remove('active');
});
λ§μ°¬κ°μ§λ‘, mouseenter
μ΄λ²€νΈμ mouseleave
μ΄λ²€νΈλ₯Ό λλ λ±λ‘νλ©΄ λ§μ°μ€κ° λ€μ΄κ° μμ λμ λμ¬ λλ₯Ό λλ
μ²λ¦¬ν μ μλ€.
λ¨μν λ§μ°μ€κ° λ€μ΄κ° μμ λμ λμ¬ λ CSS λ§ μ²λ¦¬νλ κ²μ΄λΌλ©΄, κ·Έλ₯ CSS
hover
μ νμλ₯Ό μ¬μ©νλ©΄ λλ€.
νμ§λ§ JavaScript μμ λ€μ΄κ°κ³ λμ¬λ 무μΈκ° ꡬλΆν΄μ μ²λ¦¬ν λΉμ¦λμ€ λ‘μ§μ΄ μ‘΄μ¬νλ€λ©΄, μμ κ°μ΄ mouseenter
μ΄λ²€νΈμ mouseleave
μ΄λ²€νΈλ₯Ό λλ μ²λ¦¬ν΄μΌνλ€.
5. Mose Move
const childEl = document.querySelector('.child');
childEl.addEventListener('mousemove', (event) => {
console.log(event.offsetX, event.offsetY);
});
6. Context Menu
const childEl = document.querySelector('.child');
childEl.addEventListener('contextmenu', (event) => {
console.log(event);
});
λ§μ°μ€ μ°ν΄λ¦μ κ°μνλ€.
7. Wheel
<div class="parent">
<div class="child" style="height:1000px;"></div>
</div>
const parentEl = document.querySelector('.parent');
const childEl = document.querySelector('.child');
childEl.addEventListener('wheel', (event) => {
event.deltaY > 0
? console.log(`β¬ μμΉ: ${parentEl.scrollTop}`)
: console.log(`β¬ μμΉ: ${parentEl.scrollTop}`);
});
deltaY
λ₯Ό μ¬μ©ν΄ ν μ λ°©ν₯μ μ μ μκ³ , parentEl.scrollTop
μ μ¬μ©ν΄ λΆλͺ¨μ 컨ν
μ΄λ μμμ μμ μ YμΆμ Top μμΉ
λ₯Ό
μ μ μλ€.
2. Keyboard Event π©βπ»
1. Key Down
<input type="text" />
const inputEl = document.querySelector('input');
inputEl.addEventListener('keydown', (event) => {
console.log(event.key);
});
μΆλ ₯λλ νΉμν€μ κ²°κ³Όλ λ€μκ³Ό κ°λ€.
- Command:
Meta
- Option:
Alt
- Control:
Control
- Shift:
Shift
- Backspace:
Backspace
- Delete:
Delete
- Return:
Enter
- Tab:
Tab
- ESC:
Escape
- β¬:
ArrowUp
- β¬:
ArrowDown
- β¬
:
ArrowLeft
- β‘:
ArrowRight
- Space: ` `
2. Key Up
const inputEl = document.querySelector('input');
inputEl.addEventListener('keyup', (event) => {
console.log(event.key);
});
keyup
μ keydown
κ³Ό λ¬λ¦¬ ν€λ³΄λλ₯Ό λλ₯΄κ³ μμ΄λ λ°λ³΅ μ
λ ₯μ μΈμνμ§ μλλ€. ν€μμ μμ λ λ λ°μνκΈ° λλ¬Έμ΄λ€.
ν€λ³΄λμ λ°λ³΅ μ
λ ₯μ μΈμνμ§ μκΈ° λλ¬Έμ κ³Όλν μ΄λ²€νΈ νΈμΆμ λ°©μ§νλ €λ©΄ keydown
μ΄λ²€νΈ λ³΄λ€ keyup
μ΄λ²€νΈλ₯Ό μ¬μ©νλ κ²μ΄
λ μ’λ€. νμ§λ§ keyup
μ CJK
λ¬Έμμ Return(Enter)
μ
λ ₯μ λ¬Έμ κ° μμ΄ νκΈ μ
λ ₯μ Return(Enter)
λ₯Ό μΈμν νμκ°
μλ μ΄λ²€νΈλ₯Ό λ±λ‘ν λλ keyup
κ° μλ keydown
μ΄λ²€νΈλ₯Ό μ¬μ©ν΄μΌνλ€.
3. CJK
const inputEl = document.querySelector('input');
inputEl.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
console.log(event.isComposing, event.target.value);
}
});
μλ
νμΈμ~ Hello
λ₯Ό μ
λ ₯ν μνμμ Return
ν€λ₯Ό λλ₯΄λ©΄ μ½μμ μΆλ ₯λλ κ²°κ³Όλ λ€μκ³Ό κ°λ€.
fasle 'μλ
νμΈμ~ Hello'
const inputEl = document.querySelector('input');
inputEl.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
console.log(event.isComposing, event.target.value);
}
});
Hello~ μλ
νμΈμ
λ₯Ό μ
λ ₯ν μνμμ Return
ν€λ₯Ό λλ₯΄λ©΄ μ½μμ μΆλ ₯λλ κ²°κ³Όλ λ€μκ³Ό κ°λ€.
true 'Hello~ μλ
νμΈμ'
false 'Hello~ μλ
νμΈμ'
λ§μ§λ§ κΈμκ° νκΈμΌ λ Return
ν€λ₯Ό λλ₯΄λ©΄ λ¬Έμλ₯Ό κ²°ν©ν΄μΌ νκΈ° λλ¬Έμ Return
ν€ μ
λ ₯μ λ¬Έμ κ²°ν© μ /νλ‘ 2λ²μ νΈλ¦¬κ±°κ°
λ°μμ΄ λλ€. λ§μ½ μ΄κ±Έ κ³ λ €νμ§ μκ³ μλ²λ‘ μμ²μ λ³΄λΌ κ²½μ° νκΈμ΄ λ§μ§λ§μ μ
λ ₯λμλ€λ©΄ μ€λ³΅ μμ²μ 보λ΄λ μ
μ΄ λλ κ²μ΄λ€.
κ·Έλ°λ° λ¬Έμ λ keyup
μ΄λ²€νΈλ₯Ό μ°κ²°νμ κ²½μ°λ€.
const inputEl = document.querySelector('input');
inputEl.addEventListener('keyup', (event) => {
if (event.key === 'Enter') {
console.log(event.isComposing, event.target.value);
}
});
Hello~ μλ
νμΈμ
λ₯Ό μ
λ ₯νμ§λ§ κ²°κ³Όλ λ€μκ³Ό κ°λ€.
false 'Hello~ μλ
νμΈμ'
false 'Hello~ μλ
νμΈμ'
isComposing
μ΄ λ λ€ false
κ° μΆλ ₯λμ΄ κ΅¬λΆν μ μμ΄μ§κ² λ κ²μ΄λ€. Return
ν€ μ
λ ₯μ΄ λ€μ΄κ°λ μκ°μ΄ μλ
Return
ν€ μ
λ ₯μ΄ λ€μ΄κ°λ€ λΌμ§λ μκ° νΈλ¦¬κ±°κ° λ°μνκΈ° λλ¬Έμ λ¬Έμ κ²°ν© μ /νλ‘ 2λ²μ νΈλ¦¬κ±°κ° λ°μνμ§λ§, ν¨μκ° μ€νλλ
μμ μλ μ΄λ―Έ λ¬Έμ κ²°ν©μ΄ λμ΄λ²λ¦° κ²μ΄λ€.
λΈλΌμ°μ μ μ½μμ΄ μλμΌλ‘ λ¬Έμλ₯Ό κ²°ν©ν΄μ 보μ¬μ£Όμ΄μ μ°¨μ΄κ° μμ΄ λ³΄μ΄μ§λ§
# keydown
true 'Hello~ μλ
νμΈγ
γ
'
false 'Hello~ μλ
νμΈμ'
# keyup
false 'Hello~ μλ
νμΈμ'
false 'Hello~ μλ
νμΈμ'
μ€μ λ‘λ μ΄λ κ² μΆλ ₯λλ κ²μ΄λΌ μκ°νλ©΄ λλ€.
λ°λΌμ μ΄ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄μλ isComposing
μ ꡬλ³μ΄ νμνκ³ , μ΄λ₯Ό μν΄ keydown
μ΄λ²€νΈλ₯Ό μ¬μ©ν΄μΌνλ€.
keydown event
const inputEl = document.querySelector('input');
inputEl.addEventListener('keydown', (event) => {
if (event.key === 'Enter' && !event.isComposing) {
console.log(event.target.value);
}
});
event.isComposing
μ ꡬλΆμ΄ λΆκ°λ₯ν΄ λ‘μ§μ΄ 2λ² μ€νλμ΄, ν
μ€νΈ μ
λ ₯κ³Ό λμμ μ μ©λ μμμ΄ ν λ² λ λ³κ²½λλ κ²μ νμΈν μ μλ€.
keyup event
const inputEl = document.querySelector('input');
inputEl.addEventListener('keydown', (event) => {
if (event.key === 'Enter' && !event.isComposing) {
console.log(event.target.value);
}
});
event.isComposing
μ ꡬλΆμ΄ κ°λ₯ν΄ 1λ²λ§ μ€νλλ―λ‘, ν
μ€νΈ μ
λ ₯κ³Ό λμμ μ μ©λ μμμ΄ λ³νμ§ μλ κ²μ νμΈν μ μλ€.
3. Form and Focus Event π©βπ»
1. Input
<form>
<div>
<input type="text" />
<input type="password" />
</div>
<div>
<input type="radio" id="male" name="sex" value="M" />
<label for="male">Male</label>
<input type="radio" id="female" name="sex" value="F" />
<label for="female">Female</label>
</div>
<div>
<input type="checkbox" id="sms" name="sms" value="SMS" />
<label for="sms">SMS</label>
<input type="checkbox" id="email" name="email" value="Email" />
<label for="email">Email</label>
</div>
<button type="submit">μ μΆ</button>
<button type="reset">μ΄κΈ°ν</button>
</form>
form {
max-width: 200px;
padding: 10px;
background-color: darkgreen;
border: 4px solid transparent;
box-sizing: border-box;
}
form div {
box-sizing: border-box;
border: 4px solid transparent;
padding: 5px;
}
form input {
outline: none;
margin-bottom: 8px;
}
const formEl = document.querySelector('form');
formEl.addEventListener('input', (event) => {
console.log(event.target.value);
});
input
μμλ keydown, keyup μ΄λ²€νΈ μΈμλ input
μ΄λ²€νΈλ₯Ό μ¬μ©ν μ μλ€.
μ΄κ²μ input
μμ λ§€μ° μ μ©ν μ΄λ²€νΈμΈλ°, input
μ change
μ΄λ²€νΈλ₯Ό μ¬μ©νλ©΄, input:radio
λ input:checkbox
λ
λ³κ²½ μ¦μ μ΄λ²€νΈ νΈλ¦¬κ±°κ° λμ§λ§, input:text
λ μ
λ ₯μ λ§μΉκ³ λ€λ₯Έ κ³³μΌλ‘ μ΄λν΄ focus
λ₯Ό μμ΄μΌ κ°μ΄ λ³κ²½λλ―λ‘ νμ΄ν
λμ€μλ νΈλ¦¬κ±°κ° λ°μνμ§ μλλ€.
λ°λΌμ, input:text
λ input:password
λ±μ keydown
μ΄λ keyup
μ΄λ²€νΈλ₯Ό μ¬μ©νκ³ , input:radio
λ
input:checkbox
λ change
μ΄λ²€νΈλ₯Ό μ¬μ©ν΄ μ΄μν μμΌμΌνλ€.
νμ§λ§! input μ΄λ²€νΈλ λͺ¨λ input μ΄λ²€νΈμ λν΄ μ¦μ νΈλ¦¬κ±°λ₯Ό λ°μμν¨λ€.
2. Focus & Blur
form div.active {
border-color: orange;
}
const inputEls = document.querySelectorAll('input');
inputEls.forEach((el) => {
el.addEventListener('focus', () => {
el.closest('div').classList.add('active');
});
el.addEventListener('blur', () => {
el.closest('div').classList.remove('active');
});
});
input
μ focus
κ° λ°μλλ©΄, μμ μλ¦¬λ¨ΌνΈ div
컨ν
μ΄λμ border λ₯Ό μ£Όν©μμΌλ‘ λ°κΎΌλ€.
κ·Έλ°λ° μμ κ°μ μ½λλ λΆνμνκ² λ§μ μ΄λ²€νΈλ₯Ό λ±λ‘νλ€.
const formEl = document.querySelector('form');
formEl.addEventListener('focus', (event) =>
event.target.closest('div').classList.add('active')
);
formEl.addEventListener('blur', (event) =>
event.target.closest('div').classList.remove('active')
);
μ΄λ²€νΈλ₯Ό λ±λ‘νμ§λ§ μλμ΄ λμ§ μλλ€. focus
μ blur
λ Event Propagation
μ μν΄ νΈλ¦¬κ±°κ° μλνμ§ μκΈ° λλ¬Έμ΄λ€. μ νλ μ΄λ²€νΈκ° μλ μ€μ§ μλ¦¬λ¨ΌνΈ μκΈ° μμ μκ² λ°μν μ΄λ²€νΈμ λν΄μλ§
νΈλ¦¬λ¬κ° μλνλ€.
3. Focus In & Focus Out
const formEl = document.querySelector('form');
formEl.addEventListener('focusin', (event) =>
event.target.closest('div').classList.add('active')
);
formEl.addEventListener('focusout', (event) =>
event.target.closest('div').classList.remove('active')
);
μ΄λ²μλ focus
, blur
μ΄λ²€νΈλ₯Ό focusin
, focusout
μ΄λ²€νΈλ‘ λ°κΏλ³΄μ.
μ΄μ μ μμ μΌλ‘ μλνλ€. focus
, blur
μμλ μ¬μ©ν μ μμλ Bubbling μ μν΄
μ΄λ²€νΈ νΈλ¦¬κ±°κ° μλνλ κ²μ΄λ€.
focus
λ focusin
+ if(event.target === event.currentTarget)
μ κ°λ€
el.addEventListener('focus', (event) => {
// closure's body goes here
})
el.addEventListener('focusin', (event) => {
(event.target === event.currentTarget) &&
// closure's body goes here
})
blur
λ focusout
+ if(event.target === event.currentTarget)
μ κ°λ€
el.addEventListener('blur', (event) => {
// closure's body goes here
})
el.addEventListener('focusout', (event) => {
(event.target === event.currentTarget) &&
// closure's body goes here
})
μ 리νλ©΄ λ€μκ³Ό κ°λ€.
- Event Propagation μ μ΄μ©νλ €λ©΄
focusin
,focusout
μ΄λ²€νΈλ₯Ό μ¬μ©ν΄λΌ.- μλ¦¬λ¨ΌνΈ μκΈ° μμ μκ² λ°μν μ΄λ²€νΈλ§ μ΄μ©νλ €λ©΄
focus
,blur
μ΄λ²€νΈλ₯Ό μ¬μ©ν΄λΌ. μ΄κ²μfocusin
,focusout
μ΄λ²€νΈκ° μκΈ° μμ μκ²μ λ°μνμ λλ§ μλνλλ‘if (event.target === event.currentTarget)
쑰건μ μΆκ°ν κ²κ³Ό κ°λ€.
4. Submit & Reset
formEl.addEventListener('submit', (event) => {
event.preventDefault();
const data = {
id: event.target[0].value,
pw: event.target[1].value,
sex: getSex(event.currentTarget),
contact: getContacts(event.currentTarget),
};
console.log('μ μΆ', data);
});
button:submit
μ click
μ΄λ²€νΈλ₯Ό λΆμ΄λ κ² μλλΌ form
μ submit
μ΄λ²€νΈλ₯Ό λΆμ¬ μ¬μ©νλ€.
formEl.addEventListener('reset', () => {
console.log('리μ
');
});
λ§μ°¬κ°μ§λ‘ button:reset
μ click
μ΄λ²€νΈλ₯Ό λΆμ΄λ κ² μλλΌ form
μ reset
μ΄λ²€νΈλ₯Ό λΆμ¬ μ¬μ©νλ€.
λ³λμ λΉμ¦λμ€ λ‘μ§μ΄ νμνμ§ μλ€λ©΄, reset
λ²νΌμ κΈ°λ³Έ μλμ μν΄ form
μ λͺ¨λ input
μ μ΄κΈ°ν μν¨λ€
(HTML μ input:text
μ value
κ°μ΄ 미리 μ§μ λμ΄ μκ±°λ, input:radio
μ checked
κ° λ―Έλ¦¬ μ§μ λμ΄ μμ κ²½μ°
HTML μ½λμ μ΄κΈ° μνλ‘ λ리λ κ²μΌλ‘ κ° μ체λ₯Ό μ§μ°λ κ²μ΄ μλ μ΄κΈ°ν κ°λ
μ΄λ€).
4. Dispatch and Custom Event π©βπ»
1. Dispatch
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
</div>
const [child1, child2] = document.querySelectorAll('.child');
child1.addEventListener('click', (event) => {
child2.dispatchEvent(new Event('click'));
child2.dispatchEvent(new Event('wheel'));
child2.dispatchEvent(new Event('keydown'));
});
child2.addEventListener('click', () => console.log('Child2 Click'));
child2.addEventListener('wheel', () => console.log('Child2 Wheel'));
child2.addEventListener('keydown', () => console.log('Child2 Keydown'));
el.dispatchEvent()
μ Event
μΈμ€ν΄μ€λ₯Ό argument λ‘ νΈμΆνλ©΄ JavaScript μ½λλ‘ μ΄λ²€νΈλ₯Ό λ°μμν¬ μ μλ€.
2. Custom Event
const [child1, child2] = document.querySelectorAll('.child');
child1.addEventListener('click', (event) => {
child2.dispatchEvent(new Event('hogwarts'));
});
child2.addEventListener('hogwarts', () => console.log('Child2 Hogwarts'));
child2.addEventListener('click', () => console.log('Child2 Click'));
dispatchEvent
λ₯Ό μ¬μ©νλ©΄ API μ μ‘΄μ¬νμ§ μλ Custom Event λ₯Ό νΈμΆν μ μλ€.
Event
κ°μ²΄λ₯Ό μ¬μ©ν΄ Custom Event λ₯Ό νΈμΆν μ μμ§λ§, μ΄κ²μ λ¨μ§ νΈμΆλ§ ν μ μμ λΏμ΄λ€. νμ§λ§
CustomEvent
κ°μ²΄λ₯Ό μ¬μ©νλ©΄ option
μ μ€ μ μλλ°, μ΄λ option
μ detail
μ΄λΌλ property λ₯Ό ν΅ν΄
JavaScript Data λ₯Ό μ λ¬ν μ μλ€.
const [child1, child2] = document.querySelectorAll('.child');
child1.addEventListener('click', (event) => {
const detail = { name: 'μ¬κ³Ό', price: 10_000, quantity: 24, sale: false };
child2.dispatchEvent(new CustomEvent('hogwarts', { detail: detail }));
});
child2.addEventListener('hogwarts', (event) => {
console.log('Child2 Hogwarts');
console.log(event.detail);
});
child2.addEventListener('click', () => console.log('Child2 Click'));
5. Remove Event π©βπ»
1. removeEventListener
<div class="increase">Increase !</div>
<div class="log">0</div>
const increaseBtn = document.querySelector('.increase');
const log = document.querySelector('.log');
const handler = increase(log);
increaseBtn.addEventListener('click', handler);
function increase(el) {
let num;
const incraseToFive = (event) => {
if (num === undefined) num = parseInt(el.textContent);
el.textContent = ++num;
if (num >= 5) event.target.removeEventListener('click', incraseToFive);
};
return incraseToFive;
}
λ±λ‘ν μ΄λ²€νΈλ₯Ό μ κ±°νλ 첫 λ²μ§Έ λ°©λ²μ removeEventListener
λ₯Ό μ¬μ©νλ κ²μ΄λ€. μ΄λ²€νΈ μ κ±°λ₯Ό μν΄μλ λ€μ 3κ°μ§κ°
μΌμΉν΄μΌνλ€.
- Event Type
- Event Callback Functionβs Reference
- Capture Type(Bubbling or Capturing)
2. AbortController
const controller = new AbortController();
const increaseBtn = document.querySelector('.increase');
const log = document.querySelector('.log');
increaseBtn.addEventListener('click', increase(log, controller), {
signal: controller.signal,
});
function increase(el, controller) {
let num;
return () => {
if (num === undefined) num = parseInt(el.textContent);
el.textContent = ++num;
if (num >= 5) controller.abort();
};
}
AbortController
λ₯Ό μ¬μ©νλ©΄ λΉλκΈ°λ₯Ό 컨νΈλ‘€ ν μ μλ€. fetch
λ stream
κ°μ κ² μΈμλ Event Listener
μμ Macrotask Queue μ λ±λ‘λλ λΉλκΈ° ν¨μμ΄λ―λ‘ μ»¨νΈλ‘€μ΄ κ°λ₯νλ€.
AbortController
λ₯Ό μ¬μ©νλ©΄, addEventListener
λ₯Ό λ±λ‘ν λ AbortController μ μΈμ€ν΄μ€ 곡κ°μ
Callback Function μ λ±λ‘νκΈ° λλ¬Έμ 컨νΈλ‘€λ¬μ abort
λ©μλλ₯Ό νΈμΆνκΈ°λ§ νλ©΄ μ΄λ²€νΈλ₯Ό μ κ±°ν μ μλ€.
Reference
- λ°μμ , βνλ‘ νΈμλ μΉ κ°λ°μ λͺ¨λ κ² μ΄κ²©μ°¨ ν¨ν€μ§ Online.β fastcampus.co.kr. last modified unknown, Fast Campus.
- βAbortController.β MDN Web Docs. Jan. 10, 2024, accessed Apr. 12, 2024, MDN - Abort Controller.