๐Ÿชด ์„ฑ์žฅ์ผ์ง€ 2.0

์ฑ… ํ–‰๋ณตํ•œ ์ด๊ธฐ์ฃผ์˜์ž(์›จ์ธ ๋‹ค์ด์–ด)์˜ ๋‚ด์šฉ์— ์ž๊ทน๋ฐ›์•„ ์‹œ์ž‘ํ•˜๋Š” ์†Œ๋ฐ•ํ•œ ์„ฑ์žฅ๊ธฐ๋ก

์‚ด์•„์žˆ๋Š” ๊ฝƒ๊ณผ ์ฃฝ์€ ๊ฝƒ์€ ์–ด๋–ป๊ฒŒ ๊ตฌ๋ณ„ํ•˜๋Š”๊ฐ€?
์„ฑ์žฅํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์‚ด์•„ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.
์ƒ๋ช…์˜ ์œ ์ผํ•œ ์ฆ๊ฑฐ๋Š” ์„ฑ์žฅ์ด๋‹ค!

๐ŸŒณ ํ‚ค์›Œ๋“œ (1.0) ์ตœ๋Œ€ํ•œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌ, ์ถ”ํ›„์— ๋ณด๋ฉด์„œ ์Šค์Šค๋กœ ์„ค๋ช… ๐Ÿ‰ ๊ฒฝํ—˜ ์œ„์ฃผ๋กœ (2.0) ๋‹จ์ˆœ ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ๋ณด๋‹ค ๋ฌด์—‡์„ ๋ฐฐ์› ๊ณ  ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ๋Š”์ง€ ์งง๊ณ  ๊ฐ„๋‹จํ•˜๊ฒŒ ์ž‘์„ฑํ•˜์ž

Project get-shit-done

ํ”„๋กœ์ ํŠธํ•œ๋‹ค๊ณ  ๋ฐ”๋น ์„œ ์„ฑ์žฅ์ผ์ง€๋ฅผ ๋ช‡์ผ ์“ฐ์งˆ ๋ชปํ–ˆ๋‹ค.
์„ฑ์žฅ์ผ์ง€์—์„œ๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋ฉด์„œ ๋ฐฐ์šด ๊ฒƒ๋“ค์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋‚จ๊ธฐ๊ณ  ๋”ฐ๋กœ project ํƒœ๊ทธ๋กœ ์ž์„ธํžˆ ์ •๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค.

๋ชฉํ‘œ

  • ์›น ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•œ UI ๊ตฌํ˜„

JavaScript ์›น ์ปดํฌ๋„ŒํŠธ

์ง€๋‚œ ๋ช‡ ํ•ด ๋™์•ˆ ์ˆ˜๋งŽ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋ ˆ์ž„์›Œํฌ(๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)๊ฐ€ ๋“ฑ์žฅํ–ˆ๋‹ค.(์•ต๊ทค๋Ÿฌ, ๋ทฐ, ๋ฆฌ์•กํŠธ ๋“ฑ๋“ฑ)
์ด๋Ÿฐ ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์€ ๋‹ค์–‘ํ•œ ๋ฌธ์ œ๋ฅผ ํŽธํ•˜๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์—ˆ์ง€๋งŒ, ๋ฉ์น˜๊ฐ€ ํฌ๊ธฐ์— ์•ฑ์ด ๋ฌด๊ฑฐ์›Œ์ง€๊ณ  ํ”„๋ ˆ์ž„์›Œํฌ์— ์ข…์†๋œ ์ฝ”๋“œ๋ฅผ ์ƒ์‚ฐํ•˜๊ฒŒ ํ•œ๋‹ค.
์ฆ‰, ์›น ์ปดํฌ๋„ŒํŠธ๋Š” ์ด๋Ÿฐ ํ”„๋ ˆ์ž„์›Œํฌ๋„ ์ข‹์ง€๋งŒ ๋ธŒ๋ผ์šฐ์ €์˜ ํ‘œ์ค€ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•ด์„œ ์„ฑ๋Šฅ ์ข‹์€ ์•ฑ์„ ๋งŒ๋“ค์ž๋Š” ์ทจ์ง€์—์„œ ์‹œ์ž‘ํ•œ๋‹ค.
HTML, CSS, JS๋ฅผ ์ปดํฌ๋„ŒํŠธํ™”ํ•˜๊ธฐ ์œ„ํ•œ 4๊ฐœ์˜ ํ‘œ์ค€์„ ๋ฌถ์–ด์„œ ์›น ์ปดํฌ๋„ŒํŠธ๋ผ๊ณ  ํ•œ๋‹ค.
๋ฌผ๋ก  ์ด 4๊ฐ€์ง€๋ฅผ ๋ชจ๋‘ ๋™์‹œ์— ์จ์•ผ๋งŒ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๊ณ  ํ”„๋ ˆ์ž„์›Œํฌ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค.
4๊ฐ€์ง€ ์ค‘ CustomElements์™€ ShadowDOM์„ ์ง‘์ค‘ํ•ด์„œ ์‚ดํŽด๋ณด์ž.

CustomElements

๋ง ๊ทธ๋Œ€๋กœ, ๋‚ด ๋งˆ์Œ๋Œ€๋กœ ์ปค์Šคํ…€ํ•œ ์š”์†Œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
๊ฐœ์ธ์ ์œผ๋กœ ๋ฐ”๋กœ ์ฝ”๋“œ๋ฅผ ๋ณด๋Š” ํŽธ์ด ์ดํ•ด๊ฐ€ ๋น ๋ฅด๊ธฐ์— ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์ •๋ฆฌํ•œ๋‹ค.

// ์•„๋ž˜์™€ ๊ฐ™์ด HTMLElement๋ฅผ ์ƒ์†ํ•˜๋Š” ๊ฐœ๋…์œผ๋กœ ๋‚˜๋งŒ์˜ element์˜ ํด๋ž˜์Šค ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ ๋‹ค.
// ์ฐธ๊ณ ๋กœ class๋‚ด์˜ this๋Š” ์ปค์Šคํ…€ ์—˜๋ฆฌ๋จผํŠธ ๊ทธ ์ž์ฒด๋ฅผ ๋ฐ”์ธ๋”ฉํ•œ๋‹ค.
class JaydenCustom extends HTMLElement {
  constructor() {
    super();
    this.render();
  }

  // ํ•„์ˆ˜๋Š” ์•„๋‹ˆ์ง€๋งŒ, render์™€ getTemplate ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ข€๋” ์›ํ•˜๋Š” ํ˜•ํƒœ์˜ element๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
  render() {
    this.innerHTML = this.getTemplate();
  }

  getTemplate() {
    return `
        <div></div>
        <div></div>
        `;
  }

  /*
  connectedCallback: ์ปค์Šคํ…€ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์ถ”๊ฐ€๋  ๋•Œ, ํ˜ธ์ถœ๋œ๋‹ค. ์ฃผ๋กœ ์ด๊ณณ์—์„œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋‹ค๋ฃฌ๋‹ค.
  ์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•  ์ ์€ consructor์—์„œ๋Š” ์ด ์š”์†Œ๊ฐ€ `๋งŒ๋“ค์–ด์งˆ ๋•Œ`์ด๊ณ  ์—ฌ๊ธฐ๋Š” `์ถ”๊ฐ€๋  ๋•Œ`๋ผ๋Š” ์ ์ด๋‹ค.
  */
  connectedCallback() {}
  // disconnectedCallback: ์ปค์Šคํ…€ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์ œ๊ฑฐ๋  ๋•Œ, ํ˜ธ์ถœ๋œ๋‹ค. ์ฃผ๋กœ ์œ„์—์„œ ์ƒ์„ฑํ•œ ์ด๋ฒคํŠธ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ์ง€์šธ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
  disconnectedCallback() {}

  /*
  static get observedAttributes()์—์„œ๋Š” `๊ฐ์‹œํ•  ์†์„ฑ`์„ ์•Œ๋ ค์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. [] ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ์†์„ฑ์„ ์ „๋‹ฌํ•œ๋‹ค.
  */
  static get observedAttributes() {
    return [];
  }
  // ์œ„์—์„œ ๊ฐ์‹œ ๋Œ€์ƒ์ด ๋œ ์†์„ฑ์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋œ๋‹ค.
  attributeChangedCallback(name, oldValue, newValue) {}

  // ์•„๋ฌด๋ ‡๊ฒŒ๋‚˜ ์›ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  anything() {}
}

// ๋ฐ˜๋“œ์‹œ ์ด๋ ‡๊ฒŒ ์ปค์Šคํ…€ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ •์˜ํ•ด์ฃผ์–ด์•ผํ•œ๋‹ค.
// ๋˜ํ•œ, ์ปค์Šคํ…€ ์—˜๋ฆฌ๋จผํŠธ๋Š” `aaa-bbb`์™€ ๊ฐ™์€ ํ˜•์‹์˜ ํƒœ๊ทธ๋ช…์„ ๊ฐ–๋„๋ก ํ•œ๋‹ค.
customElements.define('jayden-custom', JaydenCustom);

ShadowDOM

๋ธŒ๋ผ์šฐ์ €์˜ ๋ Œ๋”๋ง ์—”์ง„์€ html์„ ํŒŒ์‹ฑํ•˜์—ฌ DOM์„ ํ˜•์„ฑํ•œ๋‹ค. ์ด ๋•Œ, ๊ฐ ์š”์†Œ๋“ค์€ ๋…ธ๋“œ๋กœ์„œ ์ž‘์šฉํ•œ๋‹ค. ๋ฌธ์ œ๋Š” ๊ฐ ๋…ธ๋“œ๊ฐ€ ๋…๋Ÿฝ์ ์ธ DOM ์˜์—ญ์„ ๊ฐ–์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค.
์ด๋ฅผ ํ•ด๊ฒฐํ•ด์ฃผ๋Š” ๊ฒƒ์ด Shadow DOM์œผ๋กœ ๋ง ๊ทธ๋Œ€๋กœ ๋ณด์ด์ง€ ์•Š๋Š” DOM์„ ๋งŒ๋“ค์–ด์ฃผ์–ด ๊ฐ ์š”์†Œ๊ฐ€ ๋…๋ฆฝ์ ์ธ ์Šคํƒ€์ผ๋ง์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ค€๋‹ค. ๋ฐ”๋กœ ์ฝ”๋“œ๋ฅผ ๋ณด์ž.

class JaydenShadow extends HTMLElement {
  constructor() {
    super();
    // this๋Š” ์ปค์Šคํ…€ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฐ”์ธ๋”ฉ, ์ฆ‰ ์ปค์Šคํ…€ ์—˜๋ฆฌ๋จผํŠธ์— shadow DOM์„ ๋ถ™์—ฌ์ค€๋‹ค.
    this.attachShadow({ mode: 'open');
    this.render();
  }

  render() {
    // ์•„๋ž˜์™€ ๊ฐ™์ด shadowDOM์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” shadowRoot๋ฅผ ์ด์šฉํ•ด์•ผํ•œ๋‹ค.
    this.shadowRoot.innerHTML = this.getTemplate();
  }

  getTemplate() {
    return `
        <style>
        div {
          background-color: tomato;
        }
        </style>
        <div></div>
        <div></div>
        `;
  }
  // ์œ„์—์„œ ์ปค์Šคํ…€ ์—˜๋ฆฌ๋จผํŠธ ๋‚ด๋ถ€(์ •ํ™•ํžˆ๋Š” ์‰๋„์šฐ๋”)์— ์†ํ•œ div๋ฅผ ์ œ์™ธํ•˜๊ณ ๋Š” ๋ฐฐ๊ฒฝ์ƒ‰(tomato) ๊ฐ’์„ ๊ฐ–์ง€ ์•Š๋Š”๋‹ค.
  // ์ฆ‰, ์ปค์Šคํ…€ ์—˜๋ฆฌ๋จผํŠธ๋งŒ์˜ ๋…์ž์ ์ธ ๊ณต๊ฐ„์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

  connectedCallback() {}
  disconnectedCallback() {}


  static get observedAttributes() {
    return [];
  }
  attributeChangedCallback(name, oldValue, newValue) {}
}


customElements.define('jayden-shadow', JaydenShadow);

์ด์™ธ์—๋„ Template Element์™€ HTML Import ๋“ฑ์˜ ์š”์†Œ๊ฐ€ ์žˆ์ง€๋งŒ, ์œ„ 2๊ฐ€์ง€๊ฐ€ HTML, CSS, JS๋ฅผ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฌถ์–ด์ฃผ๋Š” ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ด์ง€ ์•Š์„๊นŒ ์ƒ๊ฐํ•œ๋‹ค.