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 μ½”λ“œλ‘œ 이벀트λ₯Ό λ°œμƒμ‹œν‚¬ 수 μžˆλ‹€.

1
2

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 λ₯Ό ν˜ΈμΆœν•  수 μžˆλ‹€.

1
2


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'));
1
2

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;
}
Increase !
0


λ“±λ‘ν•œ 이벀트λ₯Ό μ œκ±°ν•˜λŠ” 첫 번째 방법은 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 에 λ“±λ‘λ˜λŠ” 비동기 ν•¨μˆ˜μ΄λ―€λ‘œ 컨트둀이 κ°€λŠ₯ν•˜λ‹€.

Increase !
0


AbortControllerλ₯Ό μ‚¬μš©ν•˜λ©΄, addEventListenerλ₯Ό 등둝할 λ•Œ AbortController 의 μΈμŠ€ν„΄μŠ€ 곡간에 Callback Function 을 λ“±λ‘ν•˜κΈ° λ•Œλ¬Έμ— 컨트둀러의 abort λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜κΈ°λ§Œ ν•˜λ©΄ 이벀트λ₯Ό μ œκ±°ν•  수 μžˆλ‹€.




Reference

  1. λ°•μ˜μ›…, β€œν”„λ‘ νŠΈμ—”λ“œ μ›Ή 개발의 λͺ¨λ“  것 초격차 νŒ¨ν‚€μ§€ Online.” fastcampus.co.kr. last modified unknown, Fast Campus.
  2. β€œAbortController.” MDN Web Docs. Jan. 10, 2024, accessed Apr. 12, 2024, MDN - Abort Controller.