JS중급_Shadow DOM, template

18066 단어 자바스크립트jsjs

▶️ Shadow DOM

<input type='range'>
  • 해당코드를 개발자 콘솔에서 뜯어보면, 다음과 같은 복잡한 레이아웃이 나온다. (크롬 개발자도구 - 설정 - show user agent shaodw DOM 체크)

이처럼 '일반적으로는 볼 수 없는 숨겨진 HTML'을 shadow DOM이라고 한다.


▶️ Shadow DOM 만드는 방법

  <div class='mordor'></div>

  <script>

    document.querySelector('mordor').attachShadow({mode : 'open'});
    document.querySelector('mordor').shadowRoot.innerHTML = '<p>hello</p>'  

  </script>
  • 이렇게 사용하면 div 안에 몰래 p태그를 숨길 수 있다.
  • 우선 attachShadow()하는 함수를 써서 shadowRoot를 하나 만들고, shadowRoot 여기에 원하는 html 요소를 넣으면 숨겨진다.
  • 이러한 방식은 Web Component문법과 함께 사용할때 매우 유용하다.

▶️ Shadow DOM 과 Web Component

  class alt_div extends HTMLElement{
      connectedCallback(){
          this.innerHTML = `<label>이름을 입력하세요</label><input>
              <style> label {color : red} </style>`
      }
  }

  customElements.define('custom-input', alt_div);
	<custom-input></custom-input>
	<label>왜 나도 빨갛지??</label>
  • 스타일까지 컴포넌트화 하고 싶은 경우 컴포넌트 안에 style 태그를 집어넣는게 좋다. 그런데 이렇게 label 태그를 빨간색으로 스타일링해놨는데, 이럴 경우 컴포넌트와 관계없는 다른 태그까지 오염이 발생할 수 있다.
  • 그렇다고 CSS적으로 Class를 만들어서 해결한다고 해도 다른 곳과 class가 겹치면 문제가 생긴다. 이럴 땐 스타일을 shadow DOM을 열어서 그 곳에 집어 넣으면 된다.
  class alt_div extends HTMLElement{
      connectedCallback(){
          this.attachShadow({mode : 'open'});
          this.shadowRoot.innerHTML = `<label>이름을 입력하세요</label><input>
              <style> label {color : red} </style>`
      }
  }

  customElements.define('custom-input', alt_div);
<custom-input></custom-input>
<label>이제 빨갛지 않다!</label>
  • 이렇게 Shadow DOM으로 집어넣었더니 다른 태그 스타일을 오염시키지 않는다. 그래서 대부분 Web Component를 만들 때 shadow DOM을 활용한다. 어느정도의 html 모듈화 개발이 가능해졌다.

▶️ html 임시보관함 template 태그

  <template id="template1">
      <label>이메일을 입력하세요</label><input>
      <style>label { color : red }</style>
  </template>

  <script>
      class customClass extends HTMLElement {
          connectedCallback() {
              this.attachShadow({ mode: 'open' });
              this.shadowRoot.append(template1.content.cloneNode(true));
          }
      }

      customElements.define("custom-input", customClass3);
  </script>

  <custom-input></custom-input>
  • template태그는 특수한 태그로, 여기에 적은 html은 렌더링되지 않는다.
  • 그래서 그곳에 html을 잠시 보관하고, this.shadowRoot.append(template1.content.cloneNode(true))같은 식으로 집어넣으면 된다.

▶️ 이벤트 리스너를 부착하고 싶다면

  <template id="template1">
      <label>이메일을 입력하세요.</label><input>
      <style>label { color : red }</style>
  </template>

  <script>
      class customClass extends HTMLElement {
          connectedCallback() {
              this.attachShadow({ mode: 'open' });
              this.shadowRoot.append(template1.content.cloneNode(true));

              // 이 부분을 함수로 따로 뺄 수도 있다.
              let el = this.shadowRoot.querySelector('label');
              el.addEventListener('click', function () {
                  console.log('clicked');
              })
          }
      }
      customElements.define("custom-input", customClass);
  </script>

  <custom-input></custom-input>
  • shadow DOM안의 label 태그를 누르면 콘솔창에 '클릭함'을 출력하는 이벤트 리스너를 부착하였다.
  • 이런 식으로 개발하면 자바스크립트도 컴포넌트 안에 담아서 보관할 수도 있다. 원하는 곳에서 class만 export 해서 가져다 쓰면 컴포넌트로 모듈식 개발이 가능하다.

좋은 웹페이지 즐겨찾기