웹 컴포넌트는 그 기능을 나머지 코드로부터 캡슐화하여 재사용 가능한 커스텀 엘리먼트를 생성하
고 웹 앱에서 활용할 수 있도록 해주는 다양한 기술들의 모음입니다. - mdn web docs
이는 새로운 기술이 아니고, 브라우저에서 오랜시간 사용해온 기술이라고 한다. 흔히 알고있는 html의 video 또한 이 기술이 활용되었다.
class List extends HTMLUListElement{
constructor() {
this.list = ["현정", "율무"]
this.$list.innerHTML = `
${this.list.map((name) => `<my-item name=${name}></my-item>`}`
}
}
class Item extends HTMLLIElement{
constructor() {
this.innerHTML = this.getAttribute("name")
}
}
web component를 이루고 있는 구성요소는 오피셜하게, 크게 3가지 custom elements, shadow dom, template and slot가 있는데 얘네가 뭔지 알아보자!
customized built in element, autonomus custom elements 두가지 종류로 나뉜다.
이 custom elements이 컴포넌트를 만드는 가장 기본 요소여서, 이것만 알아도 web component기반의 UI를 구축할 수 있을 것이다.
// Web Component 정의
class CarouselImage extends HTMLImageElement {
constructor() {
super();
}
connectedCallback() {
console.log(`이미지의 규격 width:
${this.width}, height: ${this.height}`)
}
}
customElements.define('carousel-image', CarouselImage, { extends: 'img' })
// HTML, Web Component 사용
<img is="carousel-image" src="https://placehold.co/600x400/png" width=300 height=300></img
spec: define(name, constructor[, options])
observedAttributes
: 정적 속성. 변경 알림이 필요한 모든 속성의 이름을 포함해야함constructor()
: web component 인스턴스 생성 시 호출connectedCallback()
: 커스텀 엘리먼트가 다큐먼트의 DOM에 추가될 때마다 호출disconnectedCallback()
: 커스텀 엘리먼트가 다큐먼트의 DOM으로부터 연결 해제될 때마다 호출adoptedCallback()
: 커스텀 엘리먼트가 새로운 다큐먼트로 이동되었을 때 호출attributeChangedCallback(name, oldValue, newValue)
: 커스텀 엘리먼트의 어트리뷰트가 추가, 제거 또는 교체되었을 때 호출캡슐화된 DOM트리를 첨부. 관련 기능을 제어할 수 있는 API 제공 ⇒ 문서 내 다른 요소와의 충돌을 방지할 수 있음
<div id="host">
</div>
const $host = document.querySelector("#host")
const shadow = $host.attachShadow({ mode: "open" }) // shadow tree
const $node = document.createElement("div")
$node.innerHTML = 'hidden'
shadow.appendChild($node)
아래와 같이 html의 template을 이용해 선언적으로 정의할 수도 있음.
<div id="host">
<template shadowrootmode="open"> // 섀도 루트를 렌더링하는 의미이고, 실제 DOM에는 표시되지않음.
<span>I'm in the shadow DOM</span>
</template>
</div>
💄 shadow dom에 스타일 설정하기
아래의 방식처럼 shadow dom에 정의된 스타일은 다른 외부 요소에 영향을 미치지 않음. 반대로 외부 스타일이 Shadow DOM 내부 요소에 영향을 주지 못함.
ex) tailwind의 스타일이 shadow dom 내부의 요소에 적용되지 않음
스타일을 설정하는 방식에는 두 가지 방식이 있으며, 둘 중 애플리케이션 성격 등 개인의 취향에 따라 선택하면 됨. 정답은 없다!
<template>
<slot>
마크업 템플릿 작성, 렌더링된 페이지에는 표시되지 않음. 말 그대로 템플릿, 문서 내 여러 곳에서 재사용할 수 있음
동일한 마크업 구조가 반복해서 재사용된다면, 이때 템플릿 기술을 html 재사용에 활용할 수 있음
1. template 선언
<template id="#my-paragraph">
<p>My paragraph</p>
</template>
2. template 사용
const $paragraphTemplate = document.getElementyById("my-paragraph")
const content = $paragraphTemplate.content
const $container = document.createElement("div")
$container.append(content.clondNode(true))
설명만 봐서는 이해가 가지않을 수 있다...😅 아래 예제를 보며 이해해보자. 이는 아주 간단한 사례로서, 프로필 유저를 보여주는 컴포넌트와 같이 아이디, 이미지 소스와 같은 데이터만 다르게 해서 보여줘야될 경우에 이러한 template, slot을 활용할 수 있다.
<!DOCTYPE html>
<html lang="en">
<head>
<script>
customElements.define(
"user-profile",
class extends HTMLElement {
constructor() {
super();
const template = document.querySelector("#profile-template");
const shadowRoot = this.attachShadow({ mode: "open" });
shadowRoot.appendChild(template.content.cloneNode(true));
}
}
);
</script>
</head>
<body>
<!-- template -->
<template id="profile-template">
<style>
div {
padding: 10px;
}
#default {
color: grey;
}
</style>
<div>
<strong>유저 아이디</strong>
<slot name="id">user id</slot>
</div>
<div>
<strong>프로필 이미지</strong>
<slot name="profile-image">
<span id="default">* 자신을 대표하는 이미지를 추가해보세요!</span>
</slot>
</div>
<div>
<strong>소개</strong>
<slot name="description">
<span id="default">* 자신에 대한 설명을 추가해보세요!</span>
</slot>
</div>
</template>
<!-- declare user-profile element -->
<user-profile>
<span slot="id">hyeondoonge</span>
<span slot="description">반갑습니다</span>
</user-profile>
<div style="height: 1px; background-color: rgb(74, 74, 74);"></div>
<user-profile>
<span slot="id">migu</span>
<img style="width: 200px; display: block" slot="profile-image" src="https://flexible.img.hani.co.kr/flexible/normal/960/960/imgdb/resize/2019/0121/00501111_20190121.JPG"></img>
</user-profile>
</body>
</html>
장점
단점
https://developer.mozilla.org/en-US/docs/Web/API/Web_components
https://github.com/mdn/web-components-examples