[JS] Web Component

Park Inhye·2024년 3월 13일
0

Javascript

목록 보기
7/7
post-thumbnail

🥕 기존 코드에서 개선하고 싶었던 점

데이터 fetching과 print

  1. 데이터 fetching하고
  2. 데이터를 완전 탐색하며 자식요소를 생성 + 데이터 대치 하고
  3. 부모 요소를 호출해서 innerHTML로 자식 요소를 DOM에 추가

문제점

  • 코드를 재사용하기 어렵다
  • 기능별로 구분하기 어렵다

시도한 방법

프레임워크/라이브러리 사용하기로 했다.

React Component를 사용하여 코드 재사용성이 개선되었으나,
간단한 페이지가 라이브러리에 의해 무거워지는 단점 발생했다.



🥹 프레임워크 컴포넌트

장점

  • 코드의 재사용성 개선
  • 캡슐화로 내부 상태 및 동작을 정의하여 외부 코드와의 충돌 방지

단점

  • 높은 러닝 커브
    • 프레임워크나 라이브러리의 문법을 별도로 학습해야한다.
  • 무거운 덩치
    • 작은 서비스에선 오버 스펙이 된다.
  • 다른 프레임워크 간 결합이 어려움 (상호운용성 Interoperability)
  • 기존 개발 방식을 유지하며 새로운 기술 도입하는 것은 매우 큰 일이 될 수 있다.

실무에서 PHP CodeIgnitor 환경에서 작업을 했는데,
코드이그나이터에 리액트 환경을 조성하는게 너무 어려워서 포기했었다.

위의 단점은 브라우저의 기능을 사용하여 해결할 수 있다.



🚀 웹 컴포넌트

웹 컴포넌트(Web Component)는 캡슐화, 웹에 대한 사용자 인터페이스 단위의 재사용에 대해 표준화 된 결과물이다.
4개의 표준을 묶어 웹 컴포넌트라 한다.

등장 배경

Web Component는 HTML5가 제공하는 요소 외에 여러 기능을 지원하는 요소가 필요하기 때문에 Web Component가 등장

예시

<p>{현재 시간}<p>
<current-time>{현재 시간}</current-time>

장점

  • 상호운용성 (Interoperability)
    • 다른 기술 스택의 프로젝트에서도 동작한다.
  • 수명 (Lifespan)
    • 상호운용 가능하므로 더 긴 수명을 갖는다.
    • 새 기술에 맞춰 재작성할 필요가 줄어든다.
  • 가용성 (Portability)
    • 특정 라이브러리나 프레임워크에 의존하지 않는다.

4개의 표준

  1. Custom Elements
    새로운 HTML 요소의 이름과 동작을 정의할 수 있는 JavaScript API의 집합
  2. Shadow DOM
    완전히 캡슐화된 sub-DOM 트리 제공으로 외부 스타일에 영향받지 않음
  3. HTML template
    <template><slot> 엘레먼트를 사용하여 재사용 가능한 HTML 마크업 템플릿 작성 가능
  4. HTML Imports (사용 안 함)
    다른 HTML 파일에서 템플릿을 가져오게 해준다.

크로스 브라우징 문제

모든 브라우저의 옛 버전에선 동작하지 않는다.



📖 Web Component의 주요 기술

Custom Elements

개발자가 직접 정의하여 Element를 사용할 수 있도록 제공되는 기능

특징

  • 기능을 캡슐화
  • HTMLElement를 상속받는 class로 구현
  • HTML 엘리먼트와 JavaScript Class를 한 몸으로 만들어서 Custom Elements의 Life Cycle을 조작
  • 구조
    • private 변수 (state)
    • private 함수
    • life cycle 조작 메소드
    • getter 함수 (state 출력)
    • 내부상태 변경하는 메소드
    • 동작 메소드

주의사항

  • 예약어 이름과의 충돌을 막기 위해, Tag 이름 작성시 케밥 표기법(-)를 사용

예시 코드

<html>
    <body>
      	<!-- NOTE: 적용 전 -->
        <div class="card" data-name="asset0">
            <img class="card-front" src="../img/asset0.svg" alt="카드 앞면" />
            <img class="card-back" src="../img/question.svg" alt="카드 뒷면" />
        </div>
      
  	    <!-- NOTE: 적용 후 -->
        <game-card></game-card>
    </body>
</html>
export class GameCard extends HTMLElement {
  // NOTE: 내부 상태(state), 내부에서만 관리한다
  #isDisabled = false;
  
  // NOTE: DOM에 추가될 때 렌더링 처리, 초기 동작 설졍
  connectedCallback() {
    ...
  }
  
  // NOTE: DOM에서 제거될 때
  disconnectedCallback() {
    ...
  }
  
  // NOTE: 속성이 추가/제거/변경될 때
  attributeChangedCallback(attrName, oldVal, newVal) {
    this[attrName] = newVal;
  }

  // NOTE: 내부 상태를 보여주는 getter 함수
  // NOTE: 이런 구조를 사용하는 이유는 isDisabled(내부 상태)가 사용하는 곳들에서 값을 일괄적으로 바뀌게(한번에 통제할 수 있개) 만들기 위함이다.
  get isDisabled() {
    return this.#isDisabled;
  }

  // NOTE: 메소드
  flip() {
	  ...
  }

  // NOTE: 내부 상태를 변경하는 함수
  disable() {
    this.#isDisabled = true;
  }
}

// NOTE: 정의
customElements.define('game-card', GameCard);

Shadow DOM

HTML과 CSS의 스코프를 독립적으로 다룰 수 있게끔 지원하는 개념 및 기능

iframe을 사용하지 않는 이유

  • http 요청이 한차례 더 일어나며
  • 별도의 페이지므로, 소비되는 리소스가 높고 느려진다.
  • 주소가 다른 도메인이면 접근이 불가하다.

특징

  • 캡슐화
    • 마크업 구조와 스타일, 동작을 숨긴다
  • 숨겨진 DOM을 요소에 부착

구조

  • Shadow tree
    • shadow DOM 내부의 DOM 트리
  • Shadow DOM
    • Shadow Root에 붙어있는 DOM
  • Shadow root
    • shadow 트리의 root 노드
    • #shadow-root
  • Shadow host
    • Shadow Root의 부모

예시 코드

<div id="spin-nav"></div>
// NOTE: <p>는 Shadow DOM이 된다.
// NOTE: document.querySelector("#spin-nav")는 shadow host가 된다.

document.querySelector("#spin-nav").attachShadow({ mode: "open" }).innerHTML = `
    <p>
        <slot name="nav1">캠페인 관리</slot>
    </p>
    <p>
        <slot name="nav2">마이 페이지</slot>
    </p>
`;

HTML template

엘레먼트들을 재사용하고 모듈화 시키기 위해 사용하는 개념 및 기술

특징

  • <template><slot>으로 렌더링되지 않는 마크업 템플릿 작성
  • DOM API들을 그대로 사용 가능
  • 스크립트와 스타일을 포함할 수 있다.
    • 템플릿에 있을 때에는 적용되지 않지만 DOM에 붙으면 적용된다.
  • HTML로 작성되어야 한다.
    • HTML과 JS 두 개의 파일이 필요하다.

예시 코드

<section class="main-container">
	<!-- Template Element Area -->
</section>

<template id="list-container">
	<ul class="items">
    <li class=item>
    	<!-- value --> 
    </li>
  </ul>
</template>

<script>
  const $mainContainer = document.querySelector('.main-container');
	const $template = document.getElementById('list-container');
  const $clone = $template.importNode($template.content, true);
 	const $li = $clone.querySelector('.item');
  
  $li.textContent = 'Hello Template Element';
  
  $mainContainer.appendChild($clone);
</script>

출처

profile
👁👄👁

0개의 댓글