웹 구성 요소 구축!섹션 1: 표준
"구성 요소"를 말할 때, 우리는 주로 독립적이고 다시 사용할 수 있는 UI를 가리키며, 작성이 완료되면, 우리는 그것을 우리가 원하는 모든 응용 프로그램에 삽입할 수 있다.화려한 상호작용 버튼, 특별한 디자인의 인용부호, 또는 오랫동안 가장 인기 있는 카드 소부품은 모두 구성 요소에 적합한 디자인 유형의 예이다.
웹에는 자신의 본체 구성 요소 모듈이 있는데, 어떤 라이브러리도 사용할 필요가 없다는 것을 아십니까?진실한 이야기!좋은 브라우저 * 와 in any framework 에서 일하는 단일 파일 구성 요소를 작성, 발표, 다시 사용할 수 있습니다.계속 읽어 봐, 어떻게 된 일인지!
개술
Web Components
는 총괄적인 용어로 네 가지 브라우저 표준을 가리키며 웹의 본체 구성 요소 모델을 공동으로 구성한다.<template>
elements DOM 섹션을 빠르게 재사용할 수 있습니다.Custom Elements JS 클래스를 사용자 정의 HTML 태그에 연결
Shadow DOM 페이지의 나머지 부분에 수치심을 숨기기
JavaScript Modules 패키지 및 발표 구성 요소
<template> 요소
The fundamental idea of components is reusable UI. To create that, we need a way to define a template for our component. If you're familiar with React, then you've probably used JSX before. If you're more an Angular type, you've likely defined templates in JavaScript template literals.
The <template>
element lets us define snippets of HTML which aren't added to the document until cloned by JavaScript. The browser only needs to parse that HTML once (e.g. when the document loads), and can then clone it cheaply whenever asked to.
Here's a (really contrived) example of the template element in action:
<template id="dialog-template">
<dialog>
<p></p>
<button>⚓️ All Ashore!</button>
</dialog>
</template>
<label>
Type a <abbr title="message"> 💌</abbr>
<input id="input"/>
</label>
<button id="clone-it"><abbr title="Go!">🦑 Ahoy!</abbr></button>
<script>
document.getElementById('clone-it').onclick = () => superAlert(input.value);
function superAlert(message) {
// get a reference to the template
const template = document.getElementById('dialog-template');
// clone or "stamp" the template's contents
const clone = template.content.cloneNode(true);
// Make any changes to the stamped content
const diag = clone.firstElementChild;
// <dialog> element polyfill
dialogPolyfill.registerDialog(diag);
diag.firstElementChild.textContent = message;
diag.lastElementChild.onclick = function closeModal() {
diag.close();
diag.remove();
}
document.body.appendChild(diag)
diag.showModal();
}
</script>
Using <template>
elements is easy and performant. I put together a silly little benchmark 간단한 표를 구축하는 세 가지 방법은 템플릿 요소 복제, DOM API 직접 사용 및 설정innerHTML
이다.클론 템플릿 요소가 가장 빠르고 DOM API는 조금 느린 반면innerHTML
은 지금까지 가장 느린 것입니다.
따라서 <template>
요소는 HTML을 한 번 해석하고 필요에 따라 여러 번 다시 사용할 수 있도록 합니다.우리가 필요로 하는 재사용 가능한 구성 요소처럼!
<template>
element에 대한 자세한 내용은 MDNDOM API을 참조하십시오.
Custom Elements
우리가 볼 두 번째 기준은 맞춤형 요소다.이것은 상자에 적힌 대로 합니다. 사용자 정의 HTML 태그를 정의할 수 있습니다.현재 당신은 간단한 구판
<div>
과 <span>
에 만족할 필요는 없지만, <super-div>
와 <wicked-span>
로 당신의 페이지를 표시할 수도 있습니다.사용자 정의 요소는 내장 요소처럼 작동한다.문서에 추가하고 자식 요소, 일반 DOM API 등을 사용합니다. 일반 요소를 사용하는 모든 곳에서 사용자 정의 요소including in popular web frameworks를 사용할 수 있습니다.
모든 사용자 정의 요소 태그 이름에는 내부 요소와 구분하기 위해 대시가 포함되어야 합니다.같은 프로그램에서
<bobs-input>
과 <sallys-input>
를 사용하고 싶을 때, 이름 충돌을 피하는 데도 도움이 된다.또한 사용자 정의 요소는 사용자 정의 속성, DOM 속성, 방법 및 비헤이비어를 가질 수 있습니다.사용자 정의 요소의 예를 사용하는 방법:
<section>
<p>Twinkle, twinkle, little <super-span animation="shine">star</super-span>.</p>
<awesome-button exuberant>Shine it!</awesome-button>
</section>
사용자 정의 요소는 JavaScript classes로 정의되고 window.customElements
방법으로 define
대상에 등록됩니다. 이 방법은 두 가지 인자가 있습니다. 하나는 요소 이름을 정의하는 문자열이고 하나는 행동을 정의하는 자바스크립트 클래스입니다.이 예는 지루한 오래된 글자
<span>
를 사용하고 이모티콘의 초능력을 부여한다!해봐.customElements.define('super-span', class SuperSpan extends HTMLElement {
/**
* `connectedCallback` is a custom-element lifecycle callback
* which fires whenever the element is added to the document
*/
connectedCallback() {
this.addEventListener('click', this.beAwesome.bind(this))
this.style.display = 'inline-block';
this.setAttribute('aria-label', this.innerText);
switch (this.innerText) {
case 'star': this.innerText = '⭐️';
}
}
/**
* You can define your own methods on your elements.
* @param {Event} event
* @return {Animation}
*/
beAwesome(event) {
let keyframes = [];
let options = {duration: 300, iterations: 5, easing: 'ease-in-out'}
switch (this.getAttribute('animation')) {
case 'shine': keyframes = [
{opacity: 1.0, blur: '0px', transform: 'rotate(0deg)'},
{opacity: 0.7, blur: '2px', transform: 'rotate(360deg)'},
{opacity: 1.0, blur: '0px', transform: 'rotate(0deg)'},
];
}
return this.animate(keyframes, options)
}
});
사용자 정의 요소는 생명주기 리셋과 관찰 속성 같은 내장 기능을 가지고 있다.우리는 뒤의 게시물에서 이러한 내용을 소개할 것이다.스포일러 경보: 읽을 수 있음all about custom elements on MDN
Shadow DOM
파일 트리에 무엇이 숨겨져 있고, 그늘 속에 숨겨져 있으며, 무고한 노드가 감히 발을 들여놓지 못하는 어두운 곳에 숨겨져 있다
아빠 아빠 아빠!그림자 돔
I am darkness. I am the night. I am Shadow DOM!
"Shadow Dom"은 이국적인 분위기가 들릴 수도 있지만, 이미 여러 해가 걸렸다는 사실이 증명된다.그림자 DOM
Shadow DOM은 HTML 문서 세그먼트로 사용자가 볼 수 있으며 문서의 나머지 부분과 분리됩니다.IFrame에서 하나의 문서를 다른 포함된 문서와 분리하는 방식과 유사하며, 그림자 뿌리는 문서의 일부분을 주 문서와 분리합니다
예를 들어 영상 요소의 컨트롤러는 실제로는 독립된 DOM 트리로 배트맨처럼 페이지의 그늘 속에서 생활한다.글로벌 스타일은 비디오 컨트롤에 영향을 주지 않으며 그 반대의 경우
왜 DOM을 격리하는 것이 좋은 일입니까?모든 규모의 웹 응용 프로그램을 처리할 때, CSS 규칙과 선택기는 곧 제어를 잃을 것이다.페이지의 한 부분에 완벽한 CSS를 작성할 수도 있습니다. 결과적으로 당신의 스타일은 팀원들에 의해 부결되었습니다.더 심각한 것은 프로그램에 추가된 새로운 내용이 아무도 눈치채지 못할 경우 기존 내용을 파괴할 수 있다는 것이다.p>
시간의 추이에 따라 사람들은 이미 이 문제를 해결하는 많은 방법을 개발해 냈다. 엄격한 명칭 약속부터'JS의 CSS'까지 그러나 특별히 만족스러운 것은 하나도 없다.shadow DOM을 통해 브라우저에 포괄적인 솔루션을 내장했습니다
Shadow DOM은 DOM 노드를 분리하여 구성 요소의 스타일을 자유롭게 설정할 수 있습니다. 프로그램의 다른 부분이 파괴될 염려가 없습니다.어려운 클래스 이름을 사용하거나 <video>
속성에 모든 내용을 채우는 대신 구성 요소의 스타일을 간단하고 직접적으로 설정할 수 있습니다:
<template id="component-template">
<style>
:host {
display: block;
}
/* These styles apply only to button Elements
* within the shadow root of this component */
button {
background: rebeccapurple;
color: inherit;
font-size: inherit;
padding: 10px;
border-radius: 4px;
/* CSS Custom Properties can pierce the shadow boundary,
* allowing users to style specific parts of components */
border: 1px solid var(--component-border-color, ivory);
width: 100%;
}
</style>
<!-- This ID is local to the shadow-root. -->
<!-- No need to worry that another #button exists. -->
<button id="button">I'm an awesome button!</button>
</template>
<style>
/* These styles affect the entire document, but not any shadow-roots inside of it */
button {
background: cornflowerblue;
color: white;
padding: 10px;
border: none;
margin-top: 20px;
}
/* Custom Elements can be styled just like normal elements.
* These styles will be applied to the element's :host */
button,
awesome-button {
width: 280px;
font-size: inherit;
}
</style>
<awesome-button></awesome-button>
<button id="button">I'm an OK button!</button>
<section id="display">
<abbr title="click">🖱</abbr> a <abbr title="button">🔲</abbr>
</section>
Shadow DOM은 웹 구성 요소의 비법입니다.바로 이 점이 그것들을 자급자족하게 만들었다.이것은 응용 프로그램의 다른 부분을 파괴할 염려가 없이 페이지에 넣을 자신감을 갖게 합니다.p>
Firefox 63부터 모든 좋은 브라우저에서 로컬로 사용할 수 있습니다
자세히 보기Shadow DOM on MDN
에는 템플릿, 사용자 정의 요소, 그림자 DOM 세 가지 기준이 있습니다. 브라우저에서 직접 실행되는 풍부한 구성 요소 UI를 작성할 수 있으며, 특별한 도구나 구축 절차가 필요하지 않습니다.네 번째 기준은 JavaScript 모듈입니다. 사용자 정의 요소로 구성된 복잡한 응용 프로그램을 고려하고 다른 사람이 사용할 수 있도록 구성 요소를 발표할 수 있습니다.p>
JavaScript Modules
우리가'모듈'이라는 단어를 사용할 때, 우리의 뜻은 하나의 독립된 소프트웨어로 자신의 범위를 포함한다는 것이다.다시 말하면 만약에 내가 어떤 모듈에서 변수<input>
를 정의한다면 나는 이 모듈에서만 이 변수를 사용할 수 있다.다른 모듈에 액세스하려면 먼저 명시적으로 내보내야 합니다
한동안 개발자들은 모듈화된 자바스크립트를 작성하는 방법을 찾고 있었지만, 최근(2015년의 규범부터 지난 1년간의 실천 중)에 이르러서야 자바스크립트는 자신의 모듈 시스템을 가지게 되었다
import { foo } from './foo.js'
const bar = 'bar'
export const baz = foo(bar)
모듈은 아직 많지만, 우리의 목적으로는 웹 구성 요소를 작성하고 발표할 수 있습니다
식욕을 자극하는 간단한 예가 있습니다
// super-span.js
const options = {duration: 300, iterations: 5, easing: 'ease-in-out'}
const keyframes = [
{opacity: 1.0, blur: '0px', transform: 'rotate(0deg)'},
{opacity: 0.7, blur: '2px', transform: 'rotate(360deg)'},
{opacity: 1.0, blur: '0px', transform: 'rotate(0deg)'},
]
const template = document.createElement('template')
template.innerHTML = `
<style>
span {
display: inline-block;
font-weight: var(--super-font-weight, bolder);
}
</style>
<span><slot></slot></span>
<abbr title="click or mouse over">🖱</abbr>
`;
customElements.define('super-span', class SuperSpan extends HTMLElement {
$(selector) {
return this.shadowRoot && this.shadowRoot.querySelector(selector)
}
constructor() {
super()
this.shine = this.shine.bind(this)
const root = this.attachShadow({mode: 'open'})
root.appendChild(template.content.cloneNode(true))
this.addEventListener('click', this.shine)
this.addEventListener('mouseover', this.shine)
}
connectedCallback() {
const slot = this.$('slot')
const [node] = slot.assignedNodes()
this.setAttribute('aria-label', node.textContent)
node.textContent = '⭐️'
}
shine(event) {
this.$('span').animate(keyframes, options)
}
});
그리고 우리 프로그램의 HTML에서:
<script type="module" src="./super-span.js"></script>
<super-span>star</super-span>
여러분, 웹 구성 요소가 얼마나 좋은지 깨달을 때입니다
현재, 당신은 뛰어난 행동과 의미를 가진 미리 만들어진 사용자 정의 요소를 문서에 쉽게 가져올 수 있으며, 구축 절차가 필요 없습니다
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Be Excellent to Each Other</title>
<script type="module" src="//unpkg.com/@power-elements/lazy-image/lazy-image.js?module"></script>
<script type="module" src="//unpkg.com/@granite-elements/granite-alert/granite-alert.js?module"></script>
<script type="module" src="//unpkg.com/@material/mwc-button/mwc-button.js?module"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>Cross-platform, Framework-Agnostic, Reusable Components</h1>
</header>
<main>
<granite-alert id="alert" level="warning" hide>
<lazy-image role="presentation"
src="//placekitten.com/1080/720"
placeholder="//web-components-resources.appspot.com/static/logo.svg"
fade
></lazy-image>
</granite-alert>
<mwc-button id="button" raised>🚀 Launch</mwc-button>
<script>
const alert = document.getElementById('alert')
const button = document.getElementById('button')
const message = document.getElementById('message')
button.onclick = () => {
alert.hide = !alert.hide;
button.textContent = alert.hide ? '🚀 Launch' : '☠️ Close'
}
</script>
</main>
</body>
</html>
Conclusion
웹 구성 요소 표준은 브라우저에서 직접 실행되는 사용자 포함, 재사용 가능한 UI를 고려할 수 있도록 해 줍니다. 번거로운 구축 절차가 필요 없습니다.이러한 구성 요소는 일반 요소를 사용하는 모든 곳에서 사용할 수 있습니다: 순수한 HTML 또는 프로그램의 프레임 드라이버 템플릿에서
다음 글인 <하느님이 보우하시기를>에서 우리는 webcomponentsjs polyfills 이 프로그램이 지원되지 않는 브라우저에도 어떻게 구성 요소를 디자인하고 프로그램을 작성하는지 배울 것이다
😀 읽어주셔서 감사합니다!😁
이 시리즈의 다음 글 보기
Lets Build Web Components! Part 2: The Polyfills
Benny Powers 🇮🇱🇨🇦 ・ 12 min read
여기서 다루는 모든 주제에 대해 일대일로 지도하고 싶으세요?
Errata
- 본고의 전 버전은
style
에서lightDOM 속성과 하위 단계를 방문하는 예시를 보여 준다.이런 업무는 반드시 연기해야 한다foo
. - 이 글이 처음 발표된 이래Microsoft has begun development on the web components standards in Edge.파티 시간!