๐งจ ์ด๋ฒคํธ
์ด๋ฒคํธ๋ ๋ง ๊ทธ๋๋ก ์ฌ๊ฑด์ ์๋ฏธํ๋ค. ์ธ์ ์ด๋ค ์์๋ก ๋ฐ์ํ ์ง ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ ์ด๋ฒคํธ๋ฅผ ๊ฐ์งํ ์ ์์ด์ผ ํ๊ณ , ๊ฐ์งํ๊ณ ๋์ ์ด๋ป๊ฒ ์ฒ๋ฆฌ ํ ์ง์ ๋ํด ์ ํด์ผ ํ๋ค. ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ ๋ ๋ธ๋ผ์ฐ์ ์๊ฒ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํจ์ผ๋ก์จ ์ด๋ฒคํธ๋ฅผ ์์ํด ๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋ฒคํธ๋ฅผ ๊ฐ์งํ๋ฉด ํด๋น ํธ๋ค๋ฌ์ ๋ฑ๋กํ ํจ์๋ฅผ ์คํํจ์ผ๋ก์จ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค. ์ ์ ํ ์ด๋ฒคํธ๋ก ๋ ๋ค์ํ ๊ธฐ๋ฅ์ ๊ตฌํํ๊ธฐ ์ํด ์ด๋ฒคํธ์ ๋ํด ์ ๋ฆฌํด ๋ณด๊ณ ์ ํ๋ค.
๐ ์ด๋ฒคํธ ํ์
์ด๋ฒคํธ๋ ์ฌ์ฉ์์ ๋ค์ํ interaction์ด ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ํ๋ถํ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ง๋ค์ด ์ค ์ ์๋ค. ํ์ง๋ง ์ ๋๋ก ์ดํดํ์ง ์๊ณ ์ฌ์ฉํ๋ค๋ฉด ๋๋ฌด ๋ง์ ์ด๋ฒคํธ๋ก ์ฑ๋ฅ์ ๋จ์ด๋จ๋ฆฌ๊ฑฐ๋, ์ํ์ง ์์ ๊ณณ์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๊ธฐ๋ ํ๋ค. ๊ทธ๋์ ์ด๋ฒคํธ ์์ฒด์ ๋ํด์๋ ์ดํด๊ฐ ํ์ํ๋ค.
์๋ฅผ ๋ค์ด ๊ฐ์ ๋ง์ฐ์ค ์ด๋ฒคํธ๋๋ผ๋ mouseenter์ mousemove๋ ํด๋น ์์์ ๋ง์ฐ์ค๊ฐ ๋ค์ด๊ฐ์ ๋์ ์์ง์ผ ๋๋ก ๋์์ ๋ณด๋ฉด ํฌ๊ฒ ๋ค๋ฅด์ง ์์ ๋ณด์ด์ง๋ง, ๋ง์ฝ api fetchingํ๋ ํจ์๊ฐ ๋ฑ๋ก๋์ด ์๋ค๋ฉด mouseenter ์ ๊ฒฝ์ฐ ์์ฒญ๋๊ฒ ๋ง์ ๋น์ฉ์ด ๋ค๊ฒ ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ชฉ์ ์ ๋ง๊ฒ ์ด๋ฒคํธ์ ์ฐ๊ฒฐํ๋ ๊ฒ์ด ๋๋ฌด๋ ์ค์ํ๋ค.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button>sensor</button>
<script>
const btn = document.querySelector("button")
// btn.addEventListener('mousemove', () => {
// console.log('move');
// console.log('data fetching'); // ์ผ์ ์์์ ๋ง์ฐ์ค๊ฐ ์์ง์ผ ๋๋ง๋ค ํธ์ถ
// });
btn.addEventListener("mouseenter", () => {
console.log("enter")
console.log("data fetching") // ์ผ์๋ก ๋ง์ฐ์ค๊ฐ ๋ค์ด๊ฐ ๋๋ง๋ค ํธ์ถ
})
</script>
</body>
</html>์ ์ ํ ์ด๋ฒคํธ๋ฅผ ๋ถ์ฌ์ค์ ํด๊ฒฐํ ์๋ ์์ง๋ง ๋ฌดํ ์คํฌ๋กค๊ณผ ์คํฌ๋กค ์ด๋ฒคํธ์ api ํธ์ถ์ ์ฐ๊ฒฐํด์ผ ํ๋ ๊ฒฝ์ฐ๋ ์๋ค. ์ด๋ด ๋๋ Throttle๊ณผ Debounce ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ด์ฉํด ์ด๋ฒคํธ๋ฅผ ์ ์ดํ ์ ์๋ค.
Debouncing
๋๋ฐ์ด์ฑ์ ์ฐ์์ ์ผ๋ก ํธ์ถ๋๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ ์ค์์ ์ฒ์ ๋๋ ๋ง์ง๋ง์ ํธ์ถ๋๋ ํจ์๋ง ํธ์ถ๋๋ ๊ฒ์ ์๋ฏธํ๋ค.
์๋ฅผ ๋ค์ด ๊ฒ์ ์ฐฝ์ ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๊ฒฐ๊ณผ์ ๋ฐ๋ผ api๋ฅผ ํธ์ถํด ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์์จ๋ค๋ฉด input์ onchange๋ก ๊ทธ๋ฅ ํธ์ถํ๊ฒ ๋๋ฉด ์ฌ์ฉ์๊ฐ ์
๋ ฅํ๋ ํ ๊ธ์, ํ ๊ธ์ ๋ชจ๋์ api ํธ์ถ์ด ๋๊ธฐ ๋๋ฌธ์ ๋ถํ์ํ ๋น์ฉ์ด ๋ฐ์ํ๋ค.
<body>
<input id="input" />
<script>
document.querySelector("#input").addEventListener("input", function (e) {
console.log("์ฌ๊ธฐ์ ajax ์์ฒญ", e.target.value)
})
</script>
</body>์ด๊ฒ์ ๋ง๊ธฐ ์ํด์ ๋๋ฐ์ด์ฑ์ ์ด์ฉํด ์ ๋ ฅํ๋ ์ค์ 200ms๋์ ์ ๋ ฅ์ด ์๋ค๋ฉด ์ ๋ ฅ์ด ๋๋ฌ๋ค๊ณ ๊ฐ์ฃผํ๊ณ api๋ฅผ ํธ์ถํ๊ฒ ํ๋ค๋ฉด, api ํธ์ถ ๋น์ฉ์ ์๋ ์ ์๋ค. ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ์ ๋ ฅ์ด ๋ ๋๋ง๋ค timer์ ํจ์๊ฐ ์๋์ง ์ฒดํฌํ๊ณ , ์๋ค๋ฉด ์ด๊ธฐํ ์์ผ ์๋กญ๊ฒ ์ ๋ ฅํ๋ค. 200ms ๋์ ์ ๋ ฅ์ด ์๋ค๋ฉด timer์ callback ํจ์๊ฐ ์คํ๋๋ค.
<html lang="en">
<body>
<input id="input" />
<script>
let timer
document.querySelector("#input").addEventListener("input", function (e) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function () {
console.log("api ์์ฒญ", e.target.value)
}, 200)
})
</script>
</body>
</html>Throttling
Throttling์ ์ผ์ ์๊ฐ ๋์ ๋ฐ์ํ ์ ์๋ ์คํ ํ์์ ์ ํ์ ๊ฑฐ๋ ๋ฐฉ์์ด๋ค. ์์ ์ธ๊ธํ๋ ๋ฌดํ ์คํฌ๋กค๊ณผ ๊ฐ์ด ์คํฌ๋กค ์ด๋ฒคํธ๋ก api๋ฅผ ํธ์ถํด์ผ ํ๋ค๋ฉด ๊ณ์ํด์ ๋ด๋ฆด ๋๋ง๋ค ์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ์์ผ ํ๋ค. ์ด๋ Throttling์ ์ด์ฉํ๋ค๋ฉด ์ผ์ ์๊ฐ ๋น ํ๋ฒ๋ง api๊ฐ ํธ์ถ๋๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ ๊ฐ์ ํ ์ ์๋ค.
<!DOCTYPE html>
<html lang="en">
<body style="height: 150vh">
<script>
let waiting = false
document.querySelector("body").addEventListener("wheel", function (e) {
if (!waiting) {
console.log("API ํธ์ถ")
waiting = true
setTimeout(() => {
waiting = false
}, 200)
}
})
</script>
</body>
</html>๐ ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ฑ๋ก๊ณผ ์ ๊ฑฐ
์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋ ํธ์ถํ๊ธฐ ์ํด ๋ฑ๋กํด๋์ ํจ์๋ค. ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ์๋ 3๊ฐ์ง๊ฐ ์กด์ฌํ๋ค.
1. ์ด๋ฒคํธ ํธ๋ค๋ฌ attribute
Attribute์ ๊ฒฝ์ฐ on์ ๋์ฌ์ ์ด๋ฒคํธ ํ์ ์ ๋ถ์ฌ์ ๋ฑ๋กํ๋ ๋ฐฉ์์ผ๋ก ๋ฆฌ์กํธ์์ ์ฃผ๋ก ์ฌ์ฉํ ๋ฐฉ๋ฒ์ด๋ค. html์์ ํ ๋นํ ๋๋ ํจ์๋ฅผ ์ง์ ์ ๋ฌํด ์ค ์ ์๊ธฐ ๋๋ฌธ์ ๋ฌธ์์ด๋ก ์ฐ๊ฒฐํ๋๋ฐ ์๋ฌต์ ์ผ๋ก attribute๊ฐ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ํจ์ ๋ชธ์ฒด๋ก ํ์ฑํด์ ํ ๋นํด์ค๋ค. vanilla JS์์ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ค๋ฉด javascript์์ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ ๋ ์ ์ ํ์ง๋ง ๋ฆฌ์กํธ์์๋ jsx๋ฌธ๋ฒ์ผ๋ก javascript๋ก html์ ๋ง๋ค๊ธฐ ๋๋ฌธ์ attribute๋ก ์ ๋ฌํด ์ค๋ค.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button onclick="sayhi()">sensor</button>
<script>
function sayhi() {
console.log("hi")
}
</script>
</body>
</html>function onclick(event) {
sayhi() // ํ ๋น๋ ํจ์
}2. ์ด๋ฒคํธ ํธ๋ค๋ฌ ์์ฑ
DOM ๋ ธ๋์๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ ์์ฑ์ ๊ฐ์ง๊ณ ์๋ค. ์์ ์ ๋ฆฌํ attribute์ฒ๋ผ on์ ๋์ฌ์ ์ด๋ฒคํธ ํ์ ์ ๋ถ์ธ ํ์ ํจ์๋ฅผ ๋ฐ์ธ๋ฉ ํด ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ ์ ์๋ค. ์ด๋ ์์ฑ์ผ๋ก ๋ฑ๋กํ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ํ๋๋ง ๋ฑ๋ก๋ ์ ์๋ค.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button>sensor</button>
<script>
const btn = document.querySelector("button")
btn.onclick = function () {
console.log("ํด๋ฆญ") // ์์ด์ ธ
}
btn.onclick = function () {
console.log("ํด๋ฆญ2") // ์ฌํ ๋น๋์ด ์คํ
}
btn.onclick = null
</script>
</body>
</html>DOM element์ ์์ฑ์ด๊ธฐ ๋๋ฌธ์ ์์จ ๋๋ ๊ฐ๋จํ๊ฒ btn.onclick=null๋ก ํด๋น ์์ฑ์ ์์ ์ค ์ ์๋ค.
3. addEventListener
addEventListner ๋ฉ์๋๋ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ์ด๋ฒคํธ ํ์ , ๋ ๋ฒ์งธ ์ธ์๋ก ์ด๋ฒคํธ ํธ๋ค๋ฌ, ์ธ ๋ฒ์งธ ์ธ์๋ก ์บก์ฒ๋ง๋จ๊ณ์์ ์ด๋ฒคํธ๋ฅผ ์บ์นํ ์ง๋ฅผ ์ ํ ์ ์๋ค. ์ด๋ฒคํธ ํธ๋ค๋ฌ ์์ฑ๊ณผ๋ ๋ฌ๋ฆฌ ์ฌ๋ฌ ๊ฐ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์ฐ๊ฒฐํ ์ ์๊ณ ์์๋๋ก ํธ์ถ๋๋ค.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button>sensor</button>
<script>
const btn = document.querySelector("button")
const click = () => {
console.log("ํด๋ฆญ")
}
btn.addEventListener("click", click)
btn.addEventListener("click", () => {
console.log("ํด๋ฆญ2")
})
btn.removeEventListner("click", click)
</script>
</body>
</html>์ญ์ ํ ๋๋ removeEventListner๋ฅผ ์ด์ฉํ๋ฉด ๋๋๋ฐ ์ด๋ addEventListenr์ ๋ฑ๋กํ ํจ์์ ๋์ผํ ํจ์๋ฅผ ์ฐธ์กฐํ๊ฒ ํด์ผ ํ๋ค.
โจ ์ด๋ฒคํธ์ ํ๋ฆ
DOM ์์์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด DOM ํธ๋ฆฌ๋ฅผ ๋ฐ๋ผ ์ฐ์์ ์ธ ๋ฐ์์ด ์ผ์ด๋๋๋ฐ ์ด๊ฒ์ event propagation์ด๋ผ ํ๊ณ window์์ event target์ผ๋ก ์ ํ๋๋ ๊ฒ์ event capturing์ด๋ผ ๋ถ๋ฅด๊ณ event target์์ window๋ก ์ ํ๋๋ ๊ฒ์ event bubbling์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค. ํญ์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋ ๋ณ๋์ ์ฒ๋ฆฌ๊ฐ ์๋ค๋ฉด ์บก์ฒ๋ง๊ณผ ๋ฒ๋ธ๋ง์ด ์์ฐจ์ ์ผ๋ก ๋ฐ์ํ๋ค.
addEventListener์์ ์ธ๋ฒ์งธ ์ธ์๋ฅผ true๋ก ํ๊ฒ ๋๋ฉด ์บก์ฒ๋ง์์ event๋ฅผ ์บ์นํ ์ ์๊ณ , false๊ฑฐ๋ ์๋ต์์๋ ํ๊ฒ ๋จ๊ณ์ ๋ฒ๋ธ๋ง์์ event๋ฅผ ์บ์นํ ์ ์๋ค.
<!DOCTYPE html>
<html lang="en">
<body>
<p>๋ฒ๋ธ๋ง๊ณผ ์บก์ฒ๋ง<button>๋ฒํผ</button></p>
<script>
document.body.addEventListener("click", () => {
console.log("body")
})
document.querySelector("p").addEventListener(
"click",
() => {
console.log("pagragraph")
},
true
)
document.querySelector("button").addEventListener("click", () => {
console.log("button")
})
</script>
</body>
</html>
// ๊ฒฐ๊ณผ: // paragraph // button // body์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ๋ ๋ฒ์งธ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ์ธ๋ฒ์งธ ์ธ์๊ฐ true์ฌ์ ์บก์ฒ๋ง ๊ณผ์ ์์ ์ด๋ฒคํธ๋ฅผ ์บ์นํ๊ณ , ๋๋จธ์ง๋ ํ๊ฒ์ด๋ ๋ฒ๋ธ๋ง ๊ณผ์ ์์ ์ด๋ฒคํธ๋ฅผ ์บ์นํ๋ ์ํฉ์ด๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์บก์ฒ๋ง์์ ์ด๋ฒคํธ๋ฅผ ์บ์นํ๋ paragraph๊ฐ ๋จผ์ ํธ์ถ๋๊ณ ๋ ๋ฒ์งธ๋ก ํ๊ฒ ๋จ๊ณ์ธ button, ๋ง์ง๋ง์ผ๋ก ๋ฒ๋ธ๋ง ๊ณผ์ ์์ body๊ฐ ํธ์ถ๋๋ ์์๋ก ๋ํ๋๋ค.
์บก์ฒ๋ง, ํ๊ฒ, ๋ฒ๋ธ๋ง์ ์ด๋ฒคํธ ํ๋ฆ์ ์ดํดํ๋ฉด์ ์ด๋ฒคํธ๊ฐ ์์ DOM์์์์ ์บ์น๋ ์ ์๋ค๋ ๊ฒ์ ์ ์ ์๋ค. ์ด์ ์ ํ์ฉํ์ฌ ์ผ์ผ์ด ๋ชจ๋ ์์์๊ฒ ์ด๋ฒคํธํธ๋ค๋ฌ๋ฅผ ์ฐ๊ฒฐํ๋ ๊ฒ์ด ์๋๋ผ ๋ถ๋ชจ์์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์ฐ๊ฒฐํ๋ ์ด๋ฒคํธ ์์์ ๋ํด ์์๋ณด์.
์ด๋ฒคํธ ์์
<!DOCTYPE html>
<html lang="en">
<head>
<style>
#fruits {
display: flex;
list-style-type: none;
padding: 0;
}
#fruits li {
width: 100px;
cursor: pointer;
}
#fruits .active {
color: red;
text-decoration: underline;
}
</style>
</head>
<body>
<nav>
<ul id="fruits">
<li id="apple" class="active">Apple</li>
<li id="banana">banana</li>
<li id="orange">orange</li>
</ul>
</nav>
<div>์ ํ๋ ์์ดํ
: <em class="msg">apple</em></div>
<script>
const $fruits = document.getElementById("fruits")
const $msg = document.querySelector(".msg")
function activate({ target }) {
;[...$fruits.children].forEach($fruit => {
$fruit.classList.toggle("active", $fruit === target)
$msg.textContent = target.id
})
}
document.getElementById("apple").onclick = activate
document.getElementById("banana").onclick = activate
document.getElementById("orange").onclick = activate
</script>
</body>
</html>์ ์ฝ๋๋ฅผ ๋ณด๋ฉด activate๋ผ๋ ํจ์๋ฅผ liํ๊ทธ๋ง๋ค ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ก ์ฐ๊ฒฐํด์ฃผ๊ณ ์๋ค. ํ์ง๋ง ์์๊ฐ ๋์ ์ผ๋ก ์ ํด์ง๊ฑฐ๋ ์ฌ๋ฌ ๊ฐ๊ฐ ๋๋ค๋ฉด ์ผ์ผ์ด ์์ ์์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ถ์ฌ ์ฃผ๋ ๊ฒ์ ๋นํจ์จ์ ์ด๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ๋ถ๋ชจ์ธ ul์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํด ํด๊ฒฐํ ์ ์๋ค.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
#fruits {
display: flex;
list-style-type: none;
padding: 0;
}
#fruits li {
width: 100px;
cursor: pointer;
}
#fruits .active {
color: red;
text-decoration: underline;
}
</style>
</head>
<body>
<nav>
<ul id="fruits">
<li id="apple" class="active">Apple</li>
<li id="banana">banana</li>
<li id="orange">orange</li>
</ul>
</nav>
<div>์ ํ๋ ์์ดํ
: <em class="msg">apple</em></div>
<script>
const $fruits = document.getElementById("fruits")
const $msg = document.querySelector(".msg")
function activate({ target }) {
if (!target.matches("#fruits > li")) return
;[...$fruits.children].forEach($fruit => {
$fruit.classList.toggle("active", $fruit === target)
$msg.textContent = target.id
})
}
$fruits.onclick = activate
</script>
</body>
</html>์์ฝ๋์์๋ activate๊ฐ ul์๋ง ๋ฑ๋ก์ด ๋์๋ค. ์์ DOM์์์์ ์์ ์์์ event๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด์๋ ํด๋น ์ด๋ฒคํธ๊ฐ ์์์์ ๋ฐ์ํ ์ด๋ฒคํธ๊ฐ ๋ง๋์ง ์ฐ์ ์ฒดํฌํด์ผ ํ๊ธฐ ๋๋ฌธ์ if (!target.matches('#fruits > li')) return;๋ก ๋จผ์ ํ์ธํ๊ณ ๊ฐ ์์ ์์์ ์ฒ๋ฆฌํด ์ค ์ ์๋ค. ๋ฒ๋ธ๋ง์ ์ด์ฉํ ์ด๋ฒคํธ ์์์ ์ด์ฉํ๋ฉด ์ฝ๋ ์ค๋ณต์ ์ค์ผ ์ ์๋ค.
๐ โโ๏ธ ์ด๋ฒคํธ ๋ฉ์ถฐ PreventDefault()์ StopPropagation()
preventDefault()๋ ์ด๋ฒคํธ์ ๋ฉ์๋๋ก DOM์์์ ๊ธฐ๋ณธ ๋์์ ๋ง๋ ์ญํ ์ ํ๋ค. ์ฃผ๋ก form์ผ๋ก POST์์ฒญ์ ๋ณด๋ผ ๋ ์๋ก ๊ณ ์นจ์ด ์ผ์ด๋๊ฒ ๋๋๋ฐ, SPA์์๋ ์๋ก๊ณ ์นจ์ ํ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฌํ ๊ธฐ๋ณธ ๋์์ ๋ง๊ธฐ ์ํด preventDefault()๋ฅผ ์ฌ์ฉํ๋ค.
<!DOCTYPE html>
<html lang="en">
<body>
<a href="https://google.com">go</a>
<input type="checkbox" />
<form><button>์ ์ถ</button></form>
<script>
document.querySelector("a").onclick = e => {
e.preventDefault()
}
document.querySelector("input[type=checkbox]").onclick = e => {
e.preventDefault()
}
document.querySelector("form").onsubmit = e => {
e.preventDefault()
}
</script>
</body>
</html>์ ์ฝ๋์์ aํ๊ทธ์ ๊ธฐ๋ณธ ๋์์ธ ํ์ด์ง ์ด๋์ ๋ง๊ณ , checkbox input์ ๊ธฐ๋ณธ ๋์์ธ ์ฒดํฌ,ํด์ ๋ฅผ ๋ง๋๋ค.
stopPropagation์ ์ด๋ฒคํธ ์ ํ๋ฅผ ์ค์ง ์ํค๋ ๋ฐฉ๋ฒ์ผ๋ก ํด๋น ์ด๋ฒคํธ๋ฅผ ๋ถ๋ชจ ์์๋ก ๋ฒ๋ธ๋ง ๋์ง ์๊ฒ ๋ง๋๋ค. ํ๊ฒ ๊ณผ์ ์์๋ง ์ด๋ฒคํธ๋ฅผ ์บ์นํ๊ณ ์ถ์ ๋ ์ฌ์ฉํ ์ ์์ง๋ง ์ด๋ฒคํธ ํ๋ฆ์ ๋ง๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์์์น ๋ชปํ ์๋ฌ๊ฐ ๋ฐ์ํ ์ ์์ด ์กฐ์ฌํด์ ์ฌ์ฉํด์ผ ํ๋ค.
<!DOCTYPE html>
<html lang="en">
<body>
<div class="container">
<button class="btn1">button1</button>
<button class="btn2">btn2</button>
<button class="btn3">btn3</button>
</div>
<script>
document.querySelector(".container").onclick = ({ target }) => {
if (!target.matches(".container>button")) return
target.style.color = "red"
}
document.querySelector(".btn2").onclick = e => {
e.stopPropagation()
e.target.style.color = "blue"
}
</script>
</body>
</html>์ ์ฝ๋๋ฅผ ๋ณด๋ฉด btn1,2,3 ๋ชจ๋ ํด๋ฆญ ์ ๊ธ์์์ด ๋นจ๊ฐ์์ผ๋ก ๋ณํด์ผ ํ์ง๋ง btn2์ stopPropagation()์ผ๋ก btn2์ ์ด๋ฒคํธ๋ ๋ถ๋ชจ๋ก ๋ฒ๋ธ๋ง๋์ง ์์ ์์์ด ๋์ง ์๊ณ ํ๋์์ผ๋ก ์ฒ๋ฆฌ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
๐ก Event ํธ๋ค๋ฌ์ this
์ด๋ฒคํธ ํธ๋ค๋ฌ ์์ฑ์ผ๋ก ์ ๋ฌ๋๊ฑฐ๋ addEventListener()๋ก ๋ฑ๋ก๋ ํจ์ ์ ์ธ์์ this๋ ์ด๋ฒคํธ๋ฅผ ๋ฐ์ธ๋ฉํ ์์, event.currentTarget์ ๊ฐ๋ค.
<!DOCTYPE html>
<html lang="en">
<body>
<button>click me</button>
<script>
const btn = document.querySelector("button")
const handleClick = e => {
console.log(e.currentTarget) // <button>click me</button>
console.log(this) // <button>click me</button>
console.log(this === e.currentTarget) // true
}
btn.onclick = handleClick
btn.addEventListener("click", handleClick)
</script>
</body>
</html>ํ์ง๋ง ํจ์ ์ ์ธ์์ด ์๋ ํ์ดํ ํจ์์ this๋ ํ์ดํ ํจ์ ์์ฒด์ ์ผ๋ก this๋ฅผ ๊ฐ์ง ์ ์๊ธฐ ๋๋ฌธ์ ์์์ค์ฝํ์ this๋ฅผ ์ฐธ์กฐํ๋ค.
<!DOCTYPE html>
<html lang="en">
<body>
<button>click me</button>
<script>
const btn = document.querySelector("button")
const handleClick = e => {
console.log(e.currentTarget) // <button>click me</button>
console.log(this) // Window
console.log(this === e.currentTarget) // false
}
btn.onclick = handleClick
btn.addEventListener("click", handleClick)
</script>
</body>
</html>์ด๋ฌํ ์ฐจ์ด๋ ํด๋์ค์ ์ด๋ฒคํธ ํธ๋ค๋ฌ์์ this๋ฅผ ๋ฐ์ธ๋ฉ์ ํ ๋ ์ฃผ์ํด์ผ ํ ์ ์ด๋ค.
<!DOCTYPE html>
<html lang="en">
<body>
<button class="btn">0</button>
<script>
class App {
constructor() {
this.$btn = document.querySelector(".btn")
this.count = 0
// this.$btn.onclick = this.increase.bind(this);
this.$btn.onclick = this.increase
}
increase() {
console.log(this) // <button class="btn">0</button>
this.$btn.textContent = ++this.count // Uncaught TypeError: Cannot set properties of undefined (setting 'textContent')
}
}
new App()
</script>
</body>
</html>์ ์ฝ๋์์ increase๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ก ๋ฑ๋ก๋์ด์๊ธฐ ๋๋ฌธ์ this๊ฐ class๋ก ๋ง๋ค์ด์ง instance๋ฅผ ๊ฐ๋ฆฌํค๋ ๊ฒ ์๋๋ผ ์ด๋ฒคํธ๋ฅผ ๋ฐ์ธ๋ฉํ DOM ์์ this.$btn๋ฅผ ๊ฐ๋ฆฌํจ๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ this.$btn.textContent๋this.btn.textContent`์ ๊ฐ์์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
this๋ฅผ ์ธ์คํด์ค๋ก ๋ฐ์ธ๋ฉ ์์ผ์ฃผ๊ธฐ ์ํด์๋ ํจ์์ ์ง์ bind๋ก ๋ช ์์ ์ผ๋ก ์ ํด์ฃผ๊ฑฐ๋ arrow function์ ์ด์ฉํด์ class field์ this๋ฅผ ๋ฉ์๋์ ์ฐธ์กฐํ๊ฒ ํ ์ ์๋ค.
[bind๋ก this ๋ฐ์ธ๋ฉ]
<!DOCTYPE html>
<html lang="en">
<body>
<button class="btn">0</button>
<script>
class App {
constructor() {
this.$btn = document.querySelector(".btn")
this.count = 0
this.$btn.onclick = this.increase.bind(this)
}
increase() {
console.log(this) // App
this.$btn.textContent = ++this.count
}
}
new App()
</script>
</body>
</html>[arrow function]
<!DOCTYPE html>
<html lang="en">
<body>
<button class="btn">0</button>
<script>
class App {
constructor() {
this.$btn = document.querySelector(".btn")
this.count = 0
this.$btn.onclick = this.increase
}
increase = () => (this.$btn.textContent = ++this.count)
}
new App()
</script>
</body>
</html>๋ง์น๋ฉฐ
์ด๋ฒคํธ๋ฅผ ๊ณต๋ถํ๋ฉด์ ์ด์ ์ ๋ง์ฃผํ๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ด๋ถ์ this ๋ฐ์ธ๋ฉ ๋ฌธ์ ๋ฅผ ์ ๋๋ก ์ดํดํ ์ ์์๊ณ , ์ด๋ฒคํธ ์ ํ์ ์์์ ๋ํด์๋ ๋ฐ๋ฅด๊ฒ ์ ์ ์๋ ์๊ฐ์ด์๋ค.
[์ฐธ์กฐ]