Skip to content

Latest commit

ย 

History

History
213 lines (173 loc) ยท 8.59 KB

2020-10-15_JS_Event_and_CssTips.md

File metadata and controls

213 lines (173 loc) ยท 8.59 KB

JavaScript Event ์ •๋ฆฌ์™€ ์กฐ๊ฑด์  CSS ์ ์šฉ ์˜ˆ์‹œ

1. JS Event

Event

eventInheritance
๋ชจ๋“  element๋Š” node๋ฅผ ์ƒ์†ํ•˜๊ณ  ๋ชจ๋“  node๋Š” Event๋ฅผ ์ƒ์†ํ•œ๋‹ค. ์ฆ‰, ๋ชจ๋“  ์—˜๋ฆฌ๋จผํŠธ๋Š” eventTarget์ด๋‹ค.

  1. ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์ด๋ฒคํŠธ

    mouse : click, mousemove, contextmenu
    window : resize, scroll
    form : submit, reset, change, focus, blur
    ๋‹ค์–‘ํ•œ ์ด๋ฒคํŠธ ์ข…๋ฅ˜๋“ค MDN

    event.preventDefault() : ์ด๋ฒคํŠธ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ธฐ๋ณธ๊ธฐ๋Šฅ ์ทจ์†Œ (์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์˜ˆ์‹œ : submit์˜ reload๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•จ)

  2. 3๊ฐ€์ง€ event Methods

    EventTarget.addEventListener() : EventTarget์— ํŠน์ • ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ(handler)๋ฅผ ๋“ฑ๋ก
    EventTarget.removeEventListener() : EventTarget์— ์ฃผ์–ด์ง„ ์ˆ˜์‹ ๊ธฐ ์ œ๊ฑฐ
    EventTarget.dispatchEvent() : EventTarget์— ํŠน์ • ์ด๋ฒคํŠธ๋ฅผ ๋ณด๋ƒ„
    (dispatchEvent๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋™๊ธฐ์ ์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํด๋ฆญํ•˜์ง€ ์•Š์•„๋„ dispatchEvent์— ํด๋ฆญ์ด๋ฒคํŠธ๋ฅผ ๋“ฑ๋กํ•˜๋ฉด, ํด๋ฆญ์ด๋ฒคํŠธ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.)

    EventTarget Method MDN

  3. Bubbling And Capturing

    ์บก์ณ๋ง๋ฒ„๋ธ”๋ง
    ๋ฒ„๋ธ”๋ง, ์บก์ฒ˜๋ง MDN
    ์ด๋ฒคํŠธ ์บก์ฒ˜๋ง : ๋ฐ”์ธ๋”ฉ ๋˜์–ด์žˆ๋Š” ๋ถ€๋ชจ๋ถ€ํ„ฐ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ๊ฐ€ ๋ถˆ๋Ÿฌ์™€ ๋‚ด๋ ค์ ธ ์˜ค๋Š” ๊ฒƒ (์บก์ฒ˜๋ง ๋‹จ๊ณ„์—์„œ ๋ฌด์–ธ๊ฐ€ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ผ์€ ๊ฑฐ์˜ ์—†๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.)
    ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง : ์บก์ฒ˜๋ง๊ณผ ๋ฐ˜๋Œ€๋กœ ์ด๋ฒคํŠธ๊ฐ€ ์ผ์–ด๋‚œ ๋Œ€์ƒ๋ถ€ํ„ฐ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐ”์ธ๋”ฉ ๋˜์–ด์žˆ๋Š” ๋ถ€๋ชจ๊นŒ์ง€ ์˜ฌ๋ผ๊ฐ€๋Š” ๊ฒƒ (์ƒ์œ„ ๋ถ€๋ชจ์˜ ์ด๋ฒคํŠธ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.)

//sample code - ๊ฐ div์— ํด๋ฆญ์ด๋ฒคํŠธ๋ฅผ ๋“ฑ๋กํ•˜๊ณ , ์ด๋ฒคํŠธ ๋ฐœ์ƒ์‹œ, currentTarget๊ณผ target์„ ์ฝ˜์†”์— ์ถœ๋ ฅ
<body>
  <div class="parent">
    Parent
    <div class="middle">
      Middle
      <div class="child">
        Child
      </div>
    </div>
  </div>
  <script>
  const parent = document.querySelector(".parent");
  const middle = document.querySelector(".middle");
  const child = document.querySelector(".child");

  parent.addEventListener("click", ()=>{console.log("I am parent");console.log("event.currentTarget",event.currentTarget); console.log("event.target",event.target)})
  middle.addEventListener("click",  ()=>{console.log("I am something in between");console.log("event.currentTarget",event.currentTarget); console.log("event.target",event.target)})
  child.addEventListener("click", ()=>{console.log("I am child");console.log("event.currentTarget",event.currentTarget); console.log("event.target",event.target)})
  </script>
</body>
  1. Comparison - event.target & event.currentTarget

    targetAndCurrent
    event.target :์‹ค์ œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์œ„์น˜. ์ฆ‰, ๋‚ด๊ฐ€ ํด๋ฆญํ•œ ์š”์†Œ
    event.currentTarget : ์ด๋ฒคํŠธ๊ฐ€ ๋ฐ”์ธ๋”ฉ ๋˜์–ด์žˆ๋Š” ์œ„์น˜(this๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ). ์˜ˆ๋ฅผ ๋“ค๋ฉด ์ž์‹์˜ ๋ถ€๋ชจ ์š”์†Œ๊ฐ€ ๋  ์ˆ˜๋„ ์žˆ๋‹ค.

๋ฒ„๋ธ”๋ง ๋‹จ๊ณ„์—์„œ ์ƒ์œ„ ๋ถ€๋ชจ์˜ ์ด๋ฒคํŠธ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด์„œ๋Š” stopPropagation()๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ํ•˜์ง€๋งŒ, ์ด๊ฒƒ์€ ์ด๋ฒคํŠธ ์ž์ฒด๋ฅผ ๋ฌด์‹œํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ์ถ”ํ›„ ํ”„๋กœ์ ํŠธ๊ฐ€ ๋ณต์žกํ•ด์งˆ ๊ฒฝ์šฐ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์•„๋ž˜์™€ ๊ฐ™์ด ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์ด ๋” ์ข‹๋‹ค.

(event) => {
  if (event.target !== event.currentTarget) {
    return;
  }
};
  1. ์ด๋ฒคํŠธ ์œ„์ž„ (Delegation)

์ด๋ฒคํŠธ ์œ„์ž„์€ ๋น„์Šทํ•œ ๋ฐฉ์‹์œผ๋กœ ์—ฌ๋Ÿฌ ์š”์†Œ๋ฅผ ๋‹ค๋ฃฐ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค. ์š”์†Œ์— ํ• ๋‹นํ•  ์ด๋ฒคํŠธ๋ฅผ ๋ถ€๋ชจ์—๊ฒŒ ์œ„์ž„ํ•˜์—ฌ ์ž์‹์š”์†Œ ๊ฐ๊ฐ์— ์ด๋ฒคํŠธ๊ฐ€ ์ ์šฉ๋œ ํšจ๊ณผ๋ฅผ ์–ป๋Š”๋‹ค.
์•„๋ž˜์˜ ์˜ˆ์‹œ๋Š” ulํƒœ๊ทธ ์•„๋ž˜ ๊ฐ liํƒœ๊ทธ๋ฅผ ์„ ํƒ์‹œ ๋ฐฐ๊ฒฝ์ƒ‰์ด ๋ฐ”๋€Œ๊ฒŒ ํ•˜๋Š” ๊ฒฝ์šฐ์ด๋‹ค.

<style>
  .selected {
    background-color: darkgreen;
  }
</style>
<ul class="ul">
  <li>One</li>
  <li>Two</li>
  <li>Three</li>
  <li>Four</li>
  <li>Five</li>
</ul>
const ul = document.querySelector("ul");
ul.addEventListener("click", (event) => {
  if (event.target.tagName == "LI") {
    event.target.classList.add("selected");
  }
});

currentTarget๊ณผ target์„ ์ด์šฉํ•˜์—ฌ ๊ฐ ์—˜๋ฆฌ๋จผํŠธ์˜ ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ฐ ๊ฐœ๋ณ„ ๋ฆฌ์ŠคํŠธ์—๊ฒŒ ์ด๋ฒคํŠธ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋“ฑ๋กํ•œ ๊ฒƒ๊ณผ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

2. ์กฐ๊ฑด์  CSS ์‚ฌ์šฉ ์˜ˆ์‹œ

์•„๋ž˜ ์˜ˆ์‹œ๋“ค์€ React์™€ postCSS๋ฅผ ์‚ฌ์šฉํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.
(postCSS ์‚ฌ์šฉ์‹œ, ์žฅ์ ์€ ๋ชจ๋“ˆํ™”๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. app.jsx์˜ cssํŒŒ์ผ๋กœ app.module.css๋ฅผ ๋งŒ๋“ค๊ณ  app.jsx์—์„œ import styles from "./app.module.css" ํ•˜์—ฌ className={styles.ํด๋ž˜์Šค์ด๋ฆ„}์˜ ํ˜•์‹์œผ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. postCSS๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‹คํ–‰๋  ๋•Œ, ๊ฐ ํŒŒ์ผ ๋‹จ์œ„๋กœ BEM ํ˜•์‹์˜ ํด๋ž˜์Šค ์ด๋ฆ„์ด ์•Œ์•„์„œ ์ž‘์„ฑ์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํด๋ž˜์Šค ์ด๋ฆ„์ด ๊ฒน์น˜๋Š” ๊ณ ๋ ค๋ฅผ ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๊ฐœ๋ณ„ ํŒŒ์ผ์—์„œ๋งŒ ํด๋ž˜์Šค ์ด๋ฆ„์ด ๊ฒน์น˜์ง€ ์•Š๊ฒŒ ํ•ด์ฃผ๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํด๋ž˜์Šค ์ด๋ฆ„์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์ด ์ค„์–ด๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค~!)

  1. ์„ ํƒ ์š”์†Œ์— ๋”ฐ๋ฅธ ์ „์ฒด์ ์ธ ๋ ˆ์ด์•„์›ƒ ๋ณ€๊ฒฝ

๋ฆฌ์•กํŠธ์—์„œ state์˜ ์ƒํƒœ์— ๋”ฐ๋ผ ์กฐ๊ฑด๋ฌธ์„ ์‚ฌ์šฉํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์‹œ๋Š” selectedVideo๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ VideoDetail ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค. ๋˜ํ•œ, VideoList์— prop์œผ๋กœ display์— ์–ด๋–ค ์ •๋ณด๋ฅผ ๋‚ด๋ ค์ค„ ์ง€ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

return (
  //...
  <section>
    {selectedVideo && (
      <div className={styles.detail}>
        <VideoDetail video={selectedVideo} />
      </div>
    )}
    <div className={styles.list}>
      <VideoList
        videos={videos}
        onVideoClick={selectVideo}
        display={selectedVideo ? "list" : "grid"}
      />
    </div>
  </section>
);

๋‚ด๋ ค์˜จ display ์ •๋ณด์— ๋”ฐ๋ผ ํด๋ž˜์Šค์ด๋ฆ„์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค. ํด๋ž˜์Šค ์ด๋ฆ„์„ container์™€ displayType์„ ๋‹ค์ค‘์œผ๋กœ ๋„ฃ์–ด์ฃผ์–ด ์ถ”ํ›„ ์–ด๋–ค CSS๋ฅผ ๋ณด์—ฌ์ค„ ์ง€ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

const Video = memo(({ ... , display }) => {
  const displayType = display === "list" ? styles.list : styles.grid;
  return (
    <li
      className={`${styles.container} ${displayType}`}
      onClick={() => onVideoClick(video)}>)})
.container.grid {
  width: 50%;
}
.container.list {
  width: 100%;
}
  1. ์กฐ๊ฑด(loading) ์—ฌ๋ถ€์— ๋”ฐ๋ผ ์š”์†Œ์˜ ๋ทฐ์ƒํƒœ ๋ณ€๊ฒฝ

loading์„ state๋กœ ๊ด€๋ฆฌํ•˜์—ฌ loading ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋ฒ„ํŠผ์ด ๋ณด์—ฌ๊ฑฐ๋‚˜, ๋กœ๋”ฉ์Šคํ”ผ๋„ˆ๊ฐ€ ๋ณด์—ฌ์ง€๋Š” ๊ฒƒ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
!loading์ธ ๊ฒฝ์šฐ ์„ค์ •ํ•œ name ์š”์†Œ์— ๋”ฐ๋ผ ๋ฒ„ํŠผ ์ƒ‰์„ pink, grey ์ค‘ ์„ค์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

{
  !loading && (
    <button
      className={`${styles.button} ${name ? styles.pink : styles.grey}`}
      onClick={onButtonClick}
    >
      {name || "No File"}
    </button>
  );
}
{
  loading && <div className={styles.loading}></div>;
}
  1. ์„ ํƒ ์š”์†Œ์— ๋”ฐ๋ผ ๊ฐœ๋ณ„ ๋””์ž์ธ ๋ณ€๊ฒฝ

<select name="theme"> ์ž์‹ํƒœ๊ทธ์ธ <option>์—์„œ dark, light, colorful์œผ๋กœ theme๋ณ„๋กœ ์„ ํƒ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜์˜€๋‹ค.
์ด๋•Œ, ์„ ํƒ๋œ theme๋ณ„๋กœ switch๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ž˜์Šค ์ด๋ฆ„์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•˜์˜€๋‹ค.
์„ค์ •๋œ ๊ฐ’์— ๋”ฐ๋ผ ํด๋ž˜์Šค ์ด๋ฆ„์— ์ถ”๊ฐ€๋˜๋ฉฐ ๊ฐ ์ด๋ฆ„์— ๋งž๋Š” css ์„ค์ •์— ๋”ฐ๋ผ ๋””์ž์ธ ์กฐ์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์„ ํƒ์˜ ๊ฒฝ์šฐ๊ฐ€ 2๊ฐ€์ง€์ธ ๊ฒฝ์šฐ ์œ„์˜ ์˜ˆ์‹œ์™€ ๊ฐ™์ด ์‚ผํ•ญ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•œ if๋ฌธ์„ ๊ตฌ์„ฑํ•˜์˜€๋‹ค๋ฉด, ์„ ํƒ์˜ ์š”์†Œ๊ฐ€ 3๊ฐ€์ง€ ์ด์ƒ์ด ๋˜๋Š” ๊ฒฝ์šฐ switch๋ฌธ์œผ๋กœ ๊ตฌ์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

return (
    <li className={`${styles.card} ${getStyles(theme)} `}>
      <img src={url} alt="avatar" className={styles.avatar} />
    </li>
  );
})
function getStyles(theme) {
  switch (theme) {
    case "dark":
      return styles.dark;
    case "light":
      return styles.light;
    case "colorful":
      return styles.colorful;
    default:
      throw new Error(`unknown theme: ${theme}`);
  }
}
References

element MDN
๋‹ค์–‘ํ•œ ์ด๋ฒคํŠธ ์ข…๋ฅ˜๋“ค MDN
EventTarget Method MDN
์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง, ์บก์ฒ˜๋ง
๋“œ๋ฆผ์ฝ”๋”ฉ ๊ฐ•์˜๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.