Web Components

나혜수·2023년 2월 8일
0

자바스크립트 실전

목록 보기
2/19

global로 모든 것을 공유하는 DOM

HTML 문서의 모든 요소와 스타일로 구성되어 있는 DOM은 하나의 큰 global 범위 내에 있다. 따라서 모든 Element는 document 객체의 querySelector() 메소드로 접근할 수 있다. CSS 스타일 또한 글로벌 범위 내의 어떤 요소든 선택이 가능하다. 문서 전체에 무언가를 일괄 적용하고 싶을 때 이러한 방식은 매우 유용하다. 하지만, 글로벌 스타일에 영향을 받지 않는 독립적인 요소를 만들 수 없다는 점에서 불편하다. (즉, DOM API는 자체적으로 캡슐화를 지원하지 않는다.)

위에서 말한 문제를 해결하기 위해, 즉 현재 DOM에 영향 받지 않는 요소를 추가하기 위해 <iframe> 태그를 사용해왔다. iframe은 내부 프레임 (inline frame) 이라는 의미로, HTML 문서 내에서 다른 HTML 문서를 보여줄 때 사용한다. 하지만 <iframe> 태그를 사용하면 다음과 같은 단점이 있다.

  • http 요청이 한 차례 더 일어난다.
  • 별도의 페이지이기 때문에 소비되는 리소스가 높고 느리다.
  • iframe을 포함하는 페이지의 도메인과 iframe에서 불러오는 페이지의 도메인이 다르면, 크로스 도메인 설정을 위해 별도의 소스 코드가 추가되어 성능에 영향을 줄 수 있다.
  • XSS (cross site scripting) 공격에 취약하다.

→ ❗Shadow DOM을 사용하면 이러한 단점 없이 기존 DOM에 독립적인 요소를 만들 수 있다. Shadow DOM은 마크업 구조, 스타일 및 동작을 숨겨서, 페이지의 다른 코드와 충돌하지 않도록 코드를 깨끗하게 유지해 준다.

캡슐화

캡슐화는 객체 지향 프로그래밍에서 다음 2가지 측면이 있다

① 객체의 속성과 메소드를 하나의 캡슐로 묶어
② 구현 내용 일부를 내부에 은닉한다. (외부에는 필요한 부분만 노출)

캡슐 약을 떠올려보자. 우리는 캡슐 안에 어떤 색의 내용물이 있는지, 어떤 성분의 약이 들어있는지 알 수 없다. 또한 그 안의 내용물은 캡슐을 통해서 외부로부터 보호된다. 캡슐화도 이와 같다. 즉, 외부로부터 클래스에 정의된 속성과 기능들을 보호하고, 필요한 부분만 외부로 노출하여 각 객체 고유의 독립성과 책임 영역을 안전하게 지키고자 하는 목적이 있다.

자바에서는 public, default , protected, private 접근 제어자를 통해 캡슐화가 가능하다. 이를 활용해 어떤 클래스나 그 멤버에 대한 접근범위를 설정하여 데이터를 효과적으로 보호할 수 있다.

프로토타입 기반 객체지향 언어인 자바스크립트에는 이와 같은 접근 제어자가 없지만 클로저를 활용해 정보 은닉이 가능하다. → 클로저를 활용한 정보 은닉

Shadow DOM

Shadow DOM은 원래의 DOM 트리에서 분리되어 고유의 요소와 스타일을 가진, 외부에 노출되지 않은 DOM 트리이다. Shadow DOM 은 일반적인 DOM과 조작 방법 (자식 요소 추가나 스타일을 넣는 등) 에서 차이가 없지만 캡슐화를 허용한다는 점에서 다르다.

  • Shadow host : Shadow DOM이 붙어 있는 일반적인 DOM 노드

  • Shadow tree : Shadow DOM 안에 있는 DOM 트리

  • Shadow root : Shadow DOM 트리의 루트 노드

  • Shadow boundary : Shadow DOM이 끝나고 일반 DOM이 시작되는 곳

DOM과 Shadow DOM의 동일한 ID 사용
원래 DOM 내에서 id는 중복될 수 없는 값이지만 Shadow DOM은 다른 DOM으로 취급되기 때문에 DOM에서 사용한 id를 사용할 수 있다.

Shadow DOM 중첩
Shadow DOM 내에 또 다른 Shadow DOM을 생성해서 DOM, 부모 Shadow DOM과 독립적인 별개의 DOM을 중첩할 수 있다.


Shadow DOM 사용법

Shadow Root 생성

DOM Element에 Element.attachShadow() 메소드를 사용해 Shadow Root를 생성해준다. Shadow Root 아래에 생성된 Element들은 기존 DOM 영역과 별개로 관리된다. <html> 요소가 DOM의 시작인 것처럼 Shadow Root는 Shadow DOM의 시작점 역할을 한다.

let shadow = element.attachShadow({mode:'open'});
let shadow = element.attachShadow({mode:'closed'});
  • open Shadow Root 외부의 javascript를 사용하여 Shadow DOM에 접근 ⭕
    Element.shadowRoot 속성을 사용하여 접근

  • closed 접근 ❌
    Element.shadowRoot 속성을 사용하여 접근하면 null 반환
    open, close 자세히 알아보기
const newAreaEl = document.querySelector(`.new-area`);
newAreaEl.attachShadow({ mode: `open` });
<div class="new-area">
    #shadow-root (open)
</div>

이렇게 하면 newAreaEl 하위에 shadow-root가 생성된다. newAreaEl.shadowRoot를 이용해서 shadow DOM에 원하는 요소를 추가할 수 있다. 일반적인 방법과 동일하게 appendChild() 메소드를 사용하여 shadow DOM에 새로운 요소를 추가한다.
참고로 newAreaEl에서 shadowRoot 메소드를 사용하지 않고 바로 요소를 추가하면 해당 요소는 기존 DOM에 속하게 된다.

newAreaEl.shadowRoot.appendChild(document.createElement(`a`));
newAreaEl.appendChild(document.createElement(`div`));
<div class="new-area">
    #shadow-root (open)
    <a></a>
    <div></div>
</div>

Shadow DOM에 스타일 적용하기

기존 DOM과 분리 적용되는 스타일을 적용하려면 <style> 태그로 삽입해주거나, <link> 태그로 스타일 파일을 로딩하면 된다.

newAreaEl.shadowRoot.innerHTML = `<link rel="stylesheet" href="${cssFile}" />`;

const styleEl = document.createElement(`style`);
styleEl.innerText = `...`;
newAreaEl.shadowRoot.appendChild(styleEl);

웹 컴포넌트

웹 컴포넌트는 컴포넌트 기반 프로그래밍을 웹에서도 적용할 수 있도록 W3C에서 새로 정한 규격이다.
웹 컴포넌트를 이용하여 코드를 작성하면 Vue.js 프레임워크, React.js 라이브러리 등에 의존하지 않을 수 있다.

스타일링이 캡슐화되고 (Shadow Dom)
스탬프를 찍어내듯이 여러번 사용 가능한 (HTML Template)
고유한 태그를 (Custom Element)
일관된 방식으로 통합하여 사용 (ES module) 가능하도록 만든 컴포넌트이다.

참고자료
https://hanamon.kr/%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-component%EB%9E%80/

https://velog.io/@gil0127/Web-Components-%EC%BB%A4%EC%8A%A4%ED%85%80-HTML-%ED%83%9C%EA%B7%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0#%EC%BB%A4%EC%8A%A4%ED%85%80-html-%ED%83%9C%EA%B7%B8-%EB%A7%8C%EB%93%9C%EB%8A%94-%EB%B2%95

https://leeproblog.tistory.com/185

profile
오늘도 신나개 🐶

0개의 댓글