본문 바로가기

카테고리 없음

웹 컴포넌트란? (Web Component, custom element, shadowdom, template...)

728x90

웹 컴포넌트란?

바닐라 JS/HTML/CSS 등 웹표준 기반 언어를 사용하여 재사용 가능한 구성 요소를 만드는 APIs

 

 

무엇을 할 수 있을 까?

프레임워크에 종속되지 않는 독립적이며 재사용 가능한 컴포넌트 라이브러리 만들기

 

 

장점

- 커스텀화

- 재사용화

- 캡슐화

 

 

 

필수 개념

Custom element 

HTML을 확장하여 새롭게 커스텀 엘레멘트를 만들 수 있도록 지원하는 JS APIs. 라이프사이클도 지원.

class AppDrawer extends HTMLElement { ... }
window.customElements.define('app-drawer', AppDrawer);

<app-drawer></app-drawer>

Custom Elements LifeCycle Methods

- constructor() : 엘레멘트의 인스턴스가 생성되거나 업그레이드될 때 호출

- connectedCallback() : 엘레멘트가 DOM에 삽입될 때 마다 호출

- disconnectedCallback() : DOM에서 엘레멘트가 삭제될 때 마다 호출

- attributeChangeCallback(attributeName, old, Value, newValue) : 속성이 추가, 삭제, 업데이트, 대체될 때 마다 호출

 

 

Shadow Dom 

- HTML 캡슐화와 Scoped CSS 를 위해 사용한다.

- element.attachShadow({ mode: open}) 을 이용해 만들 수 있다.

- shadowRoot를 생성해, Shadow Dom에 접근하여 상호작용을 할 수 있다.

 

Template

- 캡슐화된 마크업을 정의하기 위해 사용한다.

- 템플릿 태그에 마크업과 스타일을 저장할 수 있다. 

- slot을 이용하면, Shadow Dom 내부를 커스텀 할 수 있다.

 

Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Components Example</title>
</head>
<style>
    h3 {
        color: purple;
    }
</style>
<body>
    <h3>Hello World</h3>
    <user-card 
        name="Jane"
        avatar="https://randomuser.me/api/portraits/men/1.jpg"
    >
        <div slot="email">minsangtech.kim@gmail.com</div>
        <div slot="phone">010-1234-5678</div>
    </user-card>
    <user-card 
        name="merry"
        avatar="https://randomuser.me/api/portraits/men/2.jpg"
    >
        <div slot="email">eungyeol.lee@gmail.com</div>
        <div slot="phone">010-9101-1121</div>
    </user-card>
    <script src="userCard.js"></script>
</body>
</html>

 

const template = document.createElement('template');
template.innerHTML = `
    <style>
        .user-card {
            background: #f4f4f4;
            width: 500px;
            display: grid;
            grid-template-columns: 1fr 2fr;
            grid-gap: 10px;
            margin-bottom: 15px;
            border-bottom: darkorchid 5px solid;
        }

        .user-card img {
            width: 100%;
        }

        .user-card button {
            cursor: pointer;
            background:  darkorchid;
            color: #fff;
            border: 0;
            border-radius: 5px;
            padding: 5px 10px;
        }
    </style>
    <div class="user-card">
        <img />
        <div>
            <h3></h3>
            <div class="info">
                <p><slot name="email"/></p>
                <p><slot name="phone"/></p>
            </div>
            <button id="toggle-info">Hide Info</button>
        </div>
    </div>
`;

class UserCard extends HTMLElement {
    constructor() {
        super();

        this.showInfo = true;

        this.attachShadow({ mode: 'open'});
        this.shadowRoot.appendChild(template.content.cloneNode(true)); // 이게 뭐람?
        this.shadowRoot.querySelector('h3').innerText = this.getAttribute('name');
        this.shadowRoot.querySelector('img').src = this.getAttribute('avatar');

        // 이렇게 하면 외부 DOM이랑 공유되는 상황
        // this.innerHTML = `<style>h3 { color: red; }</style><h3>${this.getAttribute('name')}</h3>`;
    }

    toggleInfo = () => {
        this.showInfo = !this.showInfo;

        const info = this.shadowRoot.querySelector('.info');
        const toggleBtn = this.shadowRoot.querySelector('#toggle-info');
        
        if(this.showInfo) {
            info.style.display = 'block';
            toggleBtn.innerText = 'Hide Info';
        } else {
            info.style.display = 'none';
            toggleBtn.innerText = 'Show Info'
        }
    }

    connectedCallback() {
        this.shadowRoot.querySelector('#toggle-info')
        .addEventListener('click', () => this.toggleInfo());
    }

    disconnectCallback() {
        this.shadowRoot.querySelector('#toggle-info')
        .removeEventListener();
    }
}

window.customElements.define('user-card', UserCard);

 

 

Custom element와 Shadow Dom의 관계

If custom elements are the way to create a new HTML (with a JS API), shadow DOM is the way you provide its HTML and CSS. The two APIs combine to make a component with self-contained HTML, CSS, and JavaScript. -> 커스텀 엘레멘트를 만드는데, 그 안의 내용을 캡슐화하면서 만들고 싶으니까 조합해서 사용하는 구나. 내부에 JS,CSS,HTML이 다 들어 있는 거임.s

 

출처 : https://youtu.be/PCWaFLy3VUo

728x90