개요
일반적으로 가능한 코드를 재사용하는 것이 좋다는 것을 알고있다. 그러나 전통적으로 마크업 구조에서는 이것이 쉽지 않았다. 때문에 현대 웹 개발을 할 때 React, Vue 와 같은 front library 를 사용해서 component based develop 을 하고있다. 그러나 React 를 사용하지 않고 순수 javascript 로도 component based develop 이 가능하다. 그것을 가능하게하는 요소들에 대해서 한 번 알아보자
Custom Element
web developer 들은 기존의 HTML tag 의 기능들을 강화하거나 확장해서 사용할 수 있다!
HTML 은 충분히 훌륭하지만 어휘 및 확장성에 제한이 있었다.
customElements 라는 명령어를 사용해 custom html 을 정의한다.
class AppDrawer extends HTMLElement {
// A getter/setter for an open property.
get open() {
return this.hasAttribute('open');
}
set open(val) {
// Reflect the value of the open property as an HTML attribute.
if (val) {
this.setAttribute('open', '');
} else {
this.removeAttribute('open');
}
this.toggleDrawer();
}
// A getter/setter for a disabled property.
get disabled() {
return this.hasAttribute('disabled');
}
set disabled(val) {
// Reflect the value of the disabled property as an HTML attribute.
if (val) {
this.setAttribute('disabled', '');
} else {
this.removeAttribute('disabled');
}
}
// Can define constructor arguments if you wish.
constructor() {
// If you define a constructor, always call super() first!
// This is specific to CE and required by the spec.
super();
// Setup a click listener on <app-drawer> itself.
this.addEventListener('click', e => {
// Don't toggle the drawer if it's disabled.
if (this.disabled) {
return;
}
this.toggleDrawer();
this.innerHTML = '<div>wow</div>'
});
}
toggleDrawer() {
...
}
}
window.customElements.define('app-drawer', AppDrawer);
JavaScript
복사
/* usage */
<app-drawer>
...
</app-drawer>
HTML
복사
class FancyButton extends HTMLButtonElement {
...
}
JavaScript
복사
기존의 HTML 을 상속받는다 ⇒ 기존 HTMLElement 의 기능을 가지고 있음. 위에서 보듯 this 를 통해서 element 에 접근이 가능하기 때문에 event 를 붙이는 등 customizing 이 가능함.
그리고 위와 같이 만들어진 custom element 또한 확장(extends)해서 새로운 custom element 를 생성 가능하다.
Default view
Search
Rules
•
custom element 의 이름은 꼭 dash 가 붙어야함.(<x-tags>, <my-element>) . html parser 가 기존 html 과 custom elements 를 구분하기 위해서임.
•
동일한 태그에 대해서는 한 번만 등록이 가능. 중복 등록 시 DOMException 발생
•
custom element 는 self closing 이 불가능함. 오직 허락된 몇 개의 tag 들만 self closing 이 가능하기 때문
Browser Support
장점
•
모듈식 코드
•
less code
•
재사용성 강화
Shadow DOM
what is shadow dom
캡슐화된 "그림자" DOM 트리를 엘리먼트 — 메인 다큐먼트 DOM 으로부터 독립적으로 렌더링 되는 — 를 추가하고 연관된 기능을 제어하기 위한 JavaScript API 의 집합. 이 방법으로 엘리먼트의 기능을 프라이빗하게 유지할 수 있어, 다큐먼트의 다른 부분과의 충돌에 대한 걱정 없이 스크립트와 스타일을 작성할 수 있음
•
shadow host - shadow dom 이 붙을 일반적인 DOM
•
shadow tree - shadow dom 의 dom tree
shadow dom 내 style 및 동작은 shadow dom 안에서만 영향을 미침. 바깥에서는 어떤 영향도 미치지 않는다.
const elementRef = document.findByElementID('container');
let shadow = elementRef.attachShadow({mode: 'open'}); // javascript 를 통해서 접근 가능
let shadow = elementRef.attachShadow({mode: 'closed'}); // " 불가능
let myShadowDom = myCustomElem.shadowRoot; // if mode closed, it will return null
myShadowDom.attachChild('<div>wow</div>');
JavaScript
복사
const header = document.createElement('header');
const shadowRoot = header.attachShadow({mode: 'open'});
shadowRoot.innerHTML = '<h1>Hello Shadow DOM</h1>'; // Could also use appendChild().
// header.shadowRoot === shadowRoot
// shadowRoot.host === header
JavaScript
복사
장점
•
캡슐화
◦
마크업 구조 및 스타일, javascript 를 페이지 내 다른 코드와 분리하고 서로 충돌하지 않으며 좋은 코드와 구조를 가지게 함.
creating shadow DOM for a custom element
customElements.define('fancy-tabs', class extends HTMLElement {
constructor() {
super(); // always call super() first in the constructor.
// Attach a shadow root to <fancy-tabs>.
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<style>#tabs { ... }</style> <!-- styles are scoped to fancy-tabs! -->
<div id="tabs">...</div>
<div id="panels">...</div>
`;
}
...
});
Plain Text
복사
browser support
HTML Template
페이지에 순간 그려지지 않지만, javascript 를 통해서 instance 를 생성할 수 있는 HTML 코드를 담을 방법을 제공.
<table id="producttable">
<thead>
<tr>
<td>UPC_Code</td>
<td>Product_Name</td>
</tr>
</thead>
<tbody>
<!-- 존재하는 데이터는 선택적으로 여기에 포함됩니다 -->
</tbody>
</table>
<template id="productrow">
<tr>
<td class="record"></td>
<td></td>
</tr>
</template>
HTML
복사
// 템플릿 엘리먼트의 컨텐츠 존재 유무를 통해
// 브라우저가 HTML 템플릿 엘리먼트를 지원하는지 확인합니다
if ('content' in document.createElement('template')) {
// 기존 HTML tbody 와 템플릿 열로 테이블을 인스턴스화합니다
var template = document.querySelector('#productrow');
// 새로운 열을 복제하고 테이블에 삽입합니다
var tb = document.querySelector("tbody");
var clone = document.importNode(template.content, true);
td = clone.querySelectorAll("td");
td[0].textContent = "1235646565";
td[1].textContent = "Stuff";
tb.appendChild(clone);
// 새로운 열을 복제하고 테이블에 삽입합니다
var clone2 = document.importNode(template.content, true);
td = clone2.querySelectorAll("td");
td[0].textContent = "0384928528";
td[1].textContent = "Acme Kidney Beans 2";
tb.appendChild(clone2);
} else {
// HTML 템플릿 엘리먼트를 지원하지 않으므로
// 테이블에 열을 추가하는 다른 방법을 찾습니다.
}
JavaScript
복사
browser support
use all
example
React vs Web Component
React와 웹 컴포넌트는 서로 다른 문제를 해결하기 위해 만들어졌습니다. 웹 컴포넌트는 재사용할 수 있는 컴포넌트에 강한 캡슐화를 제공하는 반면, React는 데이터와 DOM을 동기화하는 선언적 라이브러리를 제공합니다.
from React official website
제일 큰 차이점은 아무래도 React 로 만든 컴포넌트는 React app 에서만 사용이 가능하다는 점이다. 반면 Web component 로 만들면 Angular 든 Vue 든 React 던 상관 없이 재사용 가능하다.