맞춤 요소 v1 - 재사용 가능한 웹 구성요소

사용자설정 요소를 사용하면 웹 개발자가 새로운 HTML 태그를 정의하고, 기존 태그를 확장하며, 재사용 가능한 웹 구성 요소를 생성할 수 있습니다.

웹 개발자는 맞춤 요소를 사용하여 새 HTML 태그를 생성하고, 기존 HTML 태그를 보완하거나 다른 개발자가 보유한 구성 요소를 확장합니다. 작성했습니다. API는 웹 기반 기반으로 구성요소를 사용하여 이 작업을 수행할 수 있습니다. 웹 환경에서 재사용 가능한 구성 요소를 생성하는 표준 기반의 vanilla JS/HTML/CSS입니다. 결과적으로 코드 및 모듈식 코드 작성이 제공하게 되었습니다.

소개

브라우저는 웹 애플리케이션을 구조화하는 데 훌륭한 도구를 제공합니다. 그것은 있습니다. 들어보셨을 것입니다. Kubernetes는 선언적이고 이식적이며 쉽게 사용할 수 있습니다 HTML도 훌륭하지만, 어휘와 확장성이 제한적입니다 HTML의 살아 있는 공간 표준에는 항상 JS 동작을 마크업과 자동으로 연결합니다.

맞춤 요소는 HTML을 현대화하여 누락된 부분을 보완하는 해답입니다. 구조와 행동을 묶는 그룹 등이 있습니다. HTML이 이를 수행하는 사용자설정 요소를 만들 수 있습니다. 맞춤 요소는 HTML의 이점을 유지하면서 브라우저에 새로운 기술을 알려줍니다.

새 요소 정의

새 HTML 요소를 정의하려면 JavaScript를 사용해야 합니다.

customElements 전역은 맞춤 요소를 정의하고 자세히 알아볼 수 있습니다 태그 이름으로 customElements.define() 호출 기본 HTMLElement를 확장하는 JavaScript class 를 만듭니다.

- 모바일 창 패널 <app-drawer> 정의:

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

// Or use an anonymous class if you don't want a named constructor in current scope.
window.customElements.define('app-drawer', class extends HTMLElement {...});

사용 예:

<app-drawer></app-drawer>

맞춤 요소를 사용하는 것은 <div> 또는 다른 요소 사용 페이지에서 인스턴스를 선언할 수 있으며 이벤트 리스너를 연결할 수 있다는 등의 이점이 있습니다. 더 많은 예시를 확인하세요.

요소의 JavaScript API 정의

사용자설정 요소의 기능은 ES2015를 사용하여 정의됨 class 이는 HTMLElement를 확장합니다. HTMLElement를 확장하면 맞춤 요소가 보장됩니다. 전체 DOM API를 상속하며, 클래스가 요소의 DOM 인터페이스의 일부가 됩니다. 기본적으로 이 클래스를 사용하여 태그에 사용할 공개 JavaScript API를 만듭니다.

- <app-drawer>의 DOM 인터페이스 정의:

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();
    });
  }

  toggleDrawer() {
    // ...
  }
}

customElements.define('app-drawer', AppDrawer);

이 예에서는 open 속성 disabled가 있는 창을 만듭니다. 속성, toggleDrawer() 메서드가 있습니다. 또한 속성을 HTML로 반영함 속성을 참조하세요.

맞춤 요소의 깔끔한 기능은 클래스 정의 내부의 this가 DOM 요소 자체를 참조합니다. 즉, 클래스의 인스턴스입니다. Google의 예를 들어 this<app-drawer>를 나타냅니다. 이는 (😉) 요소가 click 리스너를 자체에 연결합니다. 이벤트 리스너로만 제한되지 않습니다. 전체 DOM API를 요소 코드 내에서 사용할 수 있습니다. this 앱을 사용하여 요소의 속성, 하위 요소 (this.children), 노드 쿼리 (this.querySelectorAll('.items')) 등

맞춤 요소 생성 규칙

  1. 맞춤 요소의 이름에는 대시 (-)가 포함되어야 합니다. 따라서 <x-tags>입니다. <my-element><my-awesome-app>는 모두 유효한 이름인 반면, <tabs>은 및 <foo_bar>는 그렇지 않습니다. 이 요구사항은 HTML 파서가 사용자설정 요소와 일반 요소를 구별할 수 있어야 합니다. 또한 kubectl run을 사용하여 호환성 문제가 발생할 수 있습니다.
  2. 같은 태그는 두 번 이상 등록할 수 없습니다. 그렇게 하려고 하면 DOMException이 발생합니다. 브라우저에 새 태그를 알리면 있습니다. 회수 불가
  3. HTML에서는 맞춤 요소가 자체적으로 닫히지 않습니다. 요소 자동으로 닫힙니다 항상 닫는 태그 작성 (<app-drawer></app-drawer>)

맞춤 요소 반응

사용자설정 요소는 알 수 있습니다. 이를 맞춤 요소라고 합니다. 반응입니다.

이름 호출 시점
constructor 요소의 인스턴스는 만들거나 업그레이드됨으로 표시됩니다. 초기화에 유용 이벤트 리스너 설정, 섀도우 DOM을 만듭니다. 자세한 내용은 <ph type="x-smartling-placeholder"></ph> 사양 를 통해 개인정보처리방침을 정의할 수 있습니다. constructor에서 수행할 수 있는 작업에 대한 제한사항을 확인하세요.
connectedCallback 호출될 때마다 요소가 DOM에 삽입됩니다. 다음과 같은 설정 코드를 실행하는 데 유용합니다. 리소스 가져오기나 렌더링에 최적화되어 있습니다 일반적으로는 작업을 지연시키고 확인할 수 있습니다.
disconnectedCallback 요소가 DOM에서 삭제될 때마다 호출됩니다. 유용한 대상 코드를 실행해 보겠습니다
attributeChangedCallback(attrName, oldVal, newVal) 관찰된 속성이 추가, 삭제, 업데이트 또는 대체될 수 있습니다. 초깃값이라고도 합니다. 요소가 파서에 의해 생성될 때 또는 업그레이드됨 참고: 다음 예시에만 적용됩니다. observedAttributes 속성에 나열된 속성은 이 콜백을 수신합니다.
adoptedCallback 이 맞춤 요소가 새 document (예: (예: document.adoptNode(el))

반응 콜백은 동기식입니다. 누군가 el.setAttribute()번으로 전화하는 경우 요소가 요소에서 즉시 attributeChangedCallback()를 호출합니다. 마찬가지로 요소가 호출된 직후에 disconnectedCallback()을 수신합니다. DOM에서 삭제됩니다 (예: 사용자가 el.remove()를 호출).

예: <app-drawer>에 맞춤 요소 반응 추가하기:

class AppDrawer extends HTMLElement {
  constructor() {
    super(); // always call super() first in the constructor.
    // ...
  }

  connectedCallback() {
    // ...
  }

  disconnectedCallback() {
    // ...
  }

  attributeChangedCallback(attrName, oldVal, newVal) {
    // ...
  }
}

적절한 경우 리액션을 정의하세요. 요소가 충분히 복잡한 경우 connectedCallback()에서 IndexedDB에 대한 연결을 열고 필요한 작업을 실행합니다. disconnectedCallback()의 정리 작업을 처리합니다. 하지만 조심해야 합니다. Kubernetes는 요소를 모든 상황에서 DOM에서 삭제해야 합니다. 예를 들어 사용자가 탭을 닫으면 disconnectedCallback()가 호출되지 않습니다.

속성 및 속성

속성을 속성에 반영

HTML 속성은 일반적으로 해당 값을 DOM에 HTML 속성입니다. 예를 들어 hidden 또는 id의 값이 자바스크립트:

div.id = 'my-id';
div.hidden = true;

값이 속성으로 라이브 DOM에 적용됩니다.

<div id="my-id" hidden>

이를 '속성을 반영하여 속성'으로 설정합니다. HTML의 거의 모든 속성이 이 작업을 수행합니다. 왜냐하면 속성은 요소와 접근성 및 CSS 같은 특정 API를 선언적으로 구성 선택기는 속성에 의존하여 작동합니다

속성을 반영하면 요소의 DOM을 유지하고 싶을 때마다 유용합니다. 자바스크립트 상태와 동기화된 상태 표시를 사용해야 합니다. 다음과 같은 한 가지 이유는 속성이 반영되므로 JS 상태가 변경될 때 사용자 정의 스타일이 적용됩니다.

<app-drawer>를 떠올려 보세요. 이 구성요소의 소비자는 페이드아웃을 원할 수 있습니다. 사용 중지될 때 사용자 상호작용을 방지할 수 있습니다.

app-drawer[disabled] {
  opacity: 0.5;
  pointer-events: none;
}

JS에서 disabled 속성이 변경되면 이 속성을 가 DOM에 추가되어 사용자의 선택기와 일치하게 됩니다. 이 요소는 같은 이름의 속성에 값을 반영하는 방식으로 동작합니다.

get disabled() {
  return this.hasAttribute('disabled');
}

set disabled(val) {
  // Reflect the value of `disabled` as an attribute.
  if (val) {
    this.setAttribute('disabled', '');
  } else {
    this.removeAttribute('disabled');
  }
  this.toggleDrawer();
}

속성 변경사항 관찰

HTML 속성은 사용자가 초기 상태를 선언할 수 있는 편리한 방법입니다.

<app-drawer open disabled></app-drawer>

요소는 속성 변경에 반응할 수 있는 attributeChangedCallback 브라우저는 변경될 때마다 이 메서드를 호출합니다. observedAttributes 배열에 나열된 속성에 연결합니다.

class AppDrawer extends HTMLElement {
  // ...

  static get observedAttributes() {
    return ['disabled', 'open'];
  }

  get disabled() {
    return this.hasAttribute('disabled');
  }

  set disabled(val) {
    if (val) {
      this.setAttribute('disabled', '');
    } else {
      this.removeAttribute('disabled');
    }
  }

  // Only called for the disabled and open attributes due to observedAttributes
  attributeChangedCallback(name, oldValue, newValue) {
    // When the drawer is disabled, update keyboard/screen reader behavior.
    if (this.disabled) {
      this.setAttribute('tabindex', '-1');
      this.setAttribute('aria-disabled', 'true');
    } else {
      this.setAttribute('tabindex', '0');
      this.setAttribute('aria-disabled', 'false');
    }
    // TODO: also react to the open attribute changing.
  }
}

이 예에서는 <app-drawer> disabled 속성이 변경되었습니다. 여기서는 하지 않지만 또한 attributeChangedCallback를 사용하여 JS 속성과 그 속성의 동기화를 유지합니다. 속성을 사용합니다.

요소 업그레이드

점진적인 HTML 개선

이미 배웠듯이 맞춤 요소는 customElements.define() 하지만 그렇다고 해서 맞춤 요소를 모두 한 번에 확인할 수 있습니다.

맞춤 요소는 정의가 등록되기 전에 사용할 수 있습니다.

점진적 개선은 맞춤 요소의 한 기능입니다. 다시 말해 페이지에서 여러 개의 <app-drawer> 요소를 선언하고 호출하지 않음 customElements.define('app-drawer', ...)입니다. 이는 브라우저는 잠재적인 맞춤 요소를 알 수 없음 태그를 참조하세요. define()를 호출하고 기존 클래스 정의가 있는 요소를 '요소 업그레이드'라고 합니다.

태그 이름이 언제 정의되는지 확인하려면 window.customElements.whenDefined() 요소가 정의됩니다.

customElements.whenDefined('app-drawer').then(() => {
  console.log('app-drawer defined');
});

- 하위 요소 집합이 업그레이드될 때까지 작업 지연

<share-buttons>
  <social-button type="twitter"><a href="...">Twitter</a></social-button>
  <social-button type="fb"><a href="...">Facebook</a></social-button>
  <social-button type="plus"><a href="...">G+</a></social-button>
</share-buttons>
// Fetch all the children of <share-buttons> that are not defined yet.
let undefinedButtons = buttons.querySelectorAll(':not(:defined)');

let promises = [...undefinedButtons].map((socialButton) => {
  return customElements.whenDefined(socialButton.localName);
});

// Wait for all the social-buttons to be upgraded.
Promise.all(promises).then(() => {
  // All social-button children are ready.
});

요소로 정의된 콘텐츠

사용자설정 요소는 내부의 DOM API를 사용하여 자체 콘텐츠를 관리할 수 있습니다. 요소 코드입니다. 이때 리액션이 유용합니다.

- 기본 HTML을 사용하여 요소 생성

customElements.define('x-foo-with-markup', class extends HTMLElement {
  connectedCallback() {
    this.innerHTML = "<b>I'm an x-foo-with-markup!</b>";
  }
  // ...
});

이 태그를 선언하면 다음이 생성됩니다.

<x-foo-with-markup>
  <b>I'm an x-foo-with-markup!</b>
</x-foo-with-markup>

// TODO: DevSite - 코드 샘플이 인라인 이벤트 핸들러를 사용하여 삭제됨

Shadow DOM을 사용하는 요소 만들기

Shadow DOM은 요소가 청크를 소유하고 렌더링하고 스타일을 지정할 수 있는 방법을 제공합니다. DOM을 사용하는 것이 좋습니다. 혹시 모를 수 있는 공격이나 앱 전체를 표시할 수 있습니다.

<!-- chat-app's implementation details are hidden away in Shadow DOM. -->
<chat-app></chat-app>

사용자설정 요소에서 Shadow DOM을 사용하려면 this.attachShadow constructor:

let tmpl = document.createElement('template');
tmpl.innerHTML = `
  <style>:host { ... }</style> <!-- look ma, scoped styles -->
  <b>I'm in shadow dom!</b>
  <slot></slot>
`;

customElements.define('x-foo-shadowdom', class extends HTMLElement {
  constructor() {
    super(); // always call super() first in the constructor.

    // Attach a shadow root to the element.
    let shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.appendChild(tmpl.content.cloneNode(true));
  }
  // ...
});

사용 예:

<x-foo-shadowdom>
  <p><b>User's</b> custom text</p>
</x-foo-shadowdom>

<!-- renders as -->
<x-foo-shadowdom>
  #shadow-root
  <b>I'm in shadow dom!</b>
  <slot></slot> <!-- slotted content appears here -->
</x-foo-shadowdom>

사용자 맞춤 텍스트

// TODO: DevSite - 코드 샘플이 인라인 이벤트 핸들러를 사용하여 삭제됨

<template>에서 요소 만들기

생소한 분들을 위해 <template> 요소 를 사용하면 파싱되고, 페이지 로드 시 비활성인 DOM의 프래그먼트를 선언할 수 있습니다. 나중에 런타임 시 활성화할 수 있습니다 이는 웹상의 또 다른 프리미티브입니다 구성요소 제품군입니다. 템플릿은 맞춤 요소의 구조입니다.

예: <template>:

<template id="x-foo-from-template">
  <style>
    p { color: green; }
  </style>
  <p>I'm in Shadow DOM. My markup was stamped from a &lt;template&gt;.</p>
</template>

<script>
  let tmpl = document.querySelector('#x-foo-from-template');
  // If your code is inside of an HTML Import you'll need to change the above line to:
  // let tmpl = document.currentScript.ownerDocument.querySelector('#x-foo-from-template');

  customElements.define('x-foo-from-template', class extends HTMLElement {
    constructor() {
      super(); // always call super() first in the constructor.
      let shadowRoot = this.attachShadow({mode: 'open'});
      shadowRoot.appendChild(tmpl.content.cloneNode(true));
    }
    // ...
  });
</script>

이 몇 줄의 코드는 강력한 효과를 제공합니다. Google Cloud에서 날짜:

  1. HTML에 새 요소(<x-foo-from-template>)를 정의합니다.
  2. 요소의 Shadow DOM이 <template>에서 생성됩니다.
  3. Shadow DOM 덕분에 요소의 DOM은 요소에 로컬입니다.
  4. 요소의 내부 CSS는 Shadow DOM 덕분에 요소로 범위가 지정됩니다.

Shadow DOM을 사용하고 있습니다. 마크업이 <template>에서 스탬프를 받았습니다.

// TODO: DevSite - 코드 샘플이 인라인 이벤트 핸들러를 사용하여 삭제됨

맞춤 요소의 스타일 지정

요소가 Shadow DOM을 사용하여 자체 스타일을 정의하더라도 사용자는 맞춤 요소를 추가합니다. 이를 '사용자 정의 스타일'이라고 합니다.

<!-- user-defined styling -->
<style>
  app-drawer {
    display: flex;
  }
  panel-item {
    transition: opacity 400ms ease-in-out;
    opacity: 0.3;
    flex: 1;
    text-align: center;
    border-radius: 50%;
  }
  panel-item:hover {
    opacity: 1.0;
    background: rgb(255, 0, 255);
    color: white;
  }
  app-panel > panel-item {
    padding: 5px;
    list-style: none;
    margin: 0 7px;
  }
</style>

<app-drawer>
  <panel-item>Do</panel-item>
  <panel-item>Re</panel-item>
  <panel-item>Mi</panel-item>
</app-drawer>

요소에 스타일이 있는 경우 CSS 특정성이 어떻게 작동하는지 자문할 수 있습니다. Shadow DOM 내에서 정의됩니다. 특정성 측면에서는 사용자 스타일이 더 좋습니다. 그들은 항상 요소 정의 스타일보다 우선 적용됩니다. 요소 만들기에 대한 섹션을 참조하세요. Shadow DOM 사용

등록되지 않은 요소의 스타일 사전 지정

요소가 업그레이드되기 전에 :defined 의사 클래스. 구성요소의 스타일을 미리 지정하는 데 유용합니다. 대상 예를 들어 정의되지 않은 것을 숨겨서 레이아웃 또는 기타 시각적 FOUC를 방지할 수 있습니다. 정의될 때 페이드인하는 것입니다.

- 정의되기 전에 <app-drawer> 숨기기:

app-drawer:not(:defined) {
  /* Pre-style, give layout, replicate app-drawer's eventual styles, etc. */
  display: inline-block;
  height: 100vh;
  opacity: 0;
  transition: opacity 0.3s ease-in-out;
}

<app-drawer>가 정의되면 선택기 (app-drawer:not(:defined)) 더 이상 일치하지 않습니다.

요소 확장

Custom Elements API는 새로운 HTML 요소를 만드는 데 유용하지만 는 다른 맞춤 요소 또는 브라우저에 내장된 HTML을 확장하는 데 유용합니다.

맞춤 요소 확장

다른 사용자설정 요소의 확장은 클래스 정의를 확장함으로써 이루어집니다.

- <app-drawer>를 확장하는 <fancy-app-drawer>를 만듭니다.

class FancyDrawer extends AppDrawer {
  constructor() {
    super(); // always call super() first in the constructor. This also calls the extended class' constructor.
    // ...
  }

  toggleDrawer() {
    // Possibly different toggle implementation?
    // Use ES2015 if you need to call the parent method.
    // super.toggleDrawer()
  }

  anotherMethod() {
    // ...
  }
}

customElements.define('fancy-app-drawer', FancyDrawer);

기본 HTML 요소 확장

예를 들어 더 화려한 <button>을(를) 만들고 싶다고 가정해 보겠습니다. 배포를 복제하는 대신 <button>의 동작과 기능을 사용하는 경우 더 나은 옵션은 맞춤 요소를 사용하여 기존 요소를 향상할 수 있습니다.

맞춤설정된 기본 제공 요소는 다음 중 하나를 확장하는 맞춤 요소입니다. 브라우저에 내장된 HTML 태그를 뜻합니다. 기존 요소의 모든 기능 (DOM 속성, 메서드, 접근성)을 얻는 것입니다. 프로그레시브 웹 작성에 이보다 좋은 방법 없음 기존 HTML을 점진적으로 개선하는 것보다 요소를 사용합니다.

요소를 확장하려면 를 사용해야 합니다. 예를 들어 <button>HTMLElement가 아닌 HTMLButtonElement에서 상속해야 합니다. 마찬가지로 <img>를 확장하는 요소는 HTMLImageElement를 확장해야 합니다.

- <button> 확장:

// See https://html.spec.whatwg.org/multipage/indices.html#element-interfaces
// for the list of other DOM interfaces.
class FancyButton extends HTMLButtonElement {
  constructor() {
    super(); // always call super() first in the constructor.
    this.addEventListener('click', e => this.drawRipple(e.offsetX, e.offsetY));
  }

  // Material design ripple animation.
  drawRipple(x, y) {
    let div = document.createElement('div');
    div.classList.add('ripple');
    this.appendChild(div);
    div.style.top = `${y - div.clientHeight/2}px`;
    div.style.left = `${x - div.clientWidth/2}px`;
    div.style.backgroundColor = 'currentColor';
    div.classList.add('run');
    div.addEventListener('transitionend', (e) => div.remove());
  }
}

customElements.define('fancy-button', FancyButton, {extends: 'button'});

네이티브를 확장할 때 define() 호출이 약간 변경됩니다. 요소가 포함됩니다. 필수 세 번째 매개변수는 사용자가 어떤 태그를 사용하고 있는지 확장할 수 있습니다 이는 많은 HTML 태그가 동일한 DOM을 공유하기 때문에 필요합니다. 인터페이스에 추가되었습니다. <section>, <address>, <em> (기타) 모두 공유 HTMLElement; <q><blockquote> 모두 HTMLQuoteElement을 공유합니다. 등... {extends: 'blockquote'}를 지정하면 브라우저가 <q> 대신 <blockquote>를 강화했습니다. HTML 사양 를 참조하세요.

맞춤설정된 기본 제공 요소의 소비자는 이 요소를 여러 가지 방식으로 사용할 수 있습니다. 사용자는 할 수 있습니다. 네이티브 태그에 is="" 속성을 추가하여 이를 선언합니다.

<!-- This <button> is a fancy button. -->
<button is="fancy-button" disabled>Fancy button!</button>

JavaScript로 인스턴스를 만듭니다.

// Custom elements overload createElement() to support the is="" attribute.
let button = document.createElement('button', {is: 'fancy-button'});
button.textContent = 'Fancy button!';
button.disabled = true;
document.body.appendChild(button);

또는 new 연산자를 사용합니다.

let button = new FancyButton();
button.textContent = 'Fancy button!';
button.disabled = true;

다음은 <img>를 확장하는 또 다른 예입니다.

- <img> 확장:

customElements.define('bigger-img', class extends Image {
  // Give img default size if users don't specify.
  constructor(width=50, height=50) {
    super(width * 10, height * 10);
  }
}, {extends: 'img'});

사용자는 이 구성요소를 다음과 같이 선언합니다.

<!-- This <img> is a bigger img. -->
<img is="bigger-img" width="15" height="20">

JavaScript로 인스턴스를 만듭니다.

const BiggerImage = customElements.get('bigger-img');
const image = new BiggerImage(15, 20); // pass constructor values like so.
console.assert(image.width === 150);
console.assert(image.height === 200);

기타 세부정보

알 수 없는 요소와 정의되지 않은 맞춤 요소 비교

HTML은 사용하기에 관대하고 유연합니다. 예를 들어, <randomtagthatdoesntexist> 상태이며 브라우저가 아주 좋음 있습니다. 비표준 태그가 작동하는 이유는 무엇인가요? 정답은 HTML 사양 허용합니다. 사양에 정의되지 않은 요소는 다음과 같이 파싱됩니다. HTMLUnknownElement

사용자설정 요소의 경우에도 마찬가지입니다. 잠재적인 맞춤 요소가 파싱됨 유효한 이름('-' 포함)으로 생성된 경우 HTMLElement로 설정합니다. 나 사용자설정 요소를 지원하는 브라우저에서 확인할 수 있습니다. 콘솔을 실행합니다. Ctrl+Shift+J (Mac에서는 Cmd+Opt+J)를 누르고 다음 코드 줄은 다음과 같습니다.

// "tabs" is not a valid custom element name
document.createElement('tabs') instanceof HTMLUnknownElement === true

// "x-tabs" is a valid custom element name
document.createElement('x-tabs') instanceof HTMLElement === true

API 참조

customElements 전역적은 맞춤 작업을 하는 데 유용한 메서드를 정의합니다. 요소

define(tagName, constructor, options)

브라우저에서 새 맞춤 요소를 정의합니다.

customElements.define('my-app', class extends HTMLElement { ... });
customElements.define(
    'fancy-button', class extends HTMLButtonElement { ... }, {extends: 'button'});

get(tagName)

유효한 사용자설정 요소 태그 이름이 지정되면 요소의 생성자를 반환합니다. 요소 정의가 등록되지 않은 경우 undefined를 반환합니다.

let Drawer = customElements.get('app-drawer');
let drawer = new Drawer();

whenDefined(tagName)

사용자설정 요소가 정의되면 이를 확인하는 프라미스를 반환합니다. 만약 요소가 이미 정의되어 있으면 즉시 확인하세요. 태그 이름이 유효한 맞춤 요소 이름이 있어야 합니다.

customElements.whenDefined('app-drawer').then(() => {
  console.log('ready!');
});

방문 기록 및 브라우저 지원

지난 몇 년간 웹 구성 요소를 알아봤다면 Chrome 36 이상에서는 맞춤 요소 API를 사용하여 customElements.define() 대신 document.registerElement() 이제 v0이라는 표준의 더 이상 사용되지 않는 버전으로 간주됩니다. 최신 인기 브라우저 및 브라우저 공급업체 customElements.define() 구현될 것입니다. 이를 사용자설정 요소 v1이라고 합니다.

이전 v0 사양에 관심이 있는 경우 HTML5rocks 도움말을 참조하세요.

브라우저 지원

Chrome 54 (상태), Safari 10.1 (상태) Firefox 63 (상태)에는 맞춤 요소 v1 Edge는 시작했습니다 참조하세요.

커스텀 요소를 감지하려면 window.customElements:

const supportsCustomElementsV1 = 'customElements' in window;

폴리필

브라우저 지원이 광범위하게 제공될 때까지는 독립형 폴리필 맞춤 요소 v1에서 사용할 수 있습니다. 대신 webcomponents.js 코드 로더 웹 구성요소 폴리필을 최적으로 로드하기 때문입니다. 로더 특성 감지를 사용하여 필요한 폴리필만 비동기식으로 로드 브라우저에서 필요로 합니다.

설치합니다.

npm install --save @webcomponents/webcomponentsjs

사용:

<!-- Use the custom element on the page. -->
<my-element></my-element>

<!-- Load polyfills; note that "loader" will load these async -->
<script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js" defer></script>

<!-- Load a custom element definitions in `waitFor` and return a promise -->
<script type="module">
  function loadScript(src) {
    return new Promise(function(resolve, reject) {
      const script = document.createElement('script');
      script.src = src;
      script.onload = resolve;
      script.onerror = reject;
      document.head.appendChild(script);
    });
  }

  WebComponents.waitFor(() => {
    // At this point we are guaranteed that all required polyfills have
    // loaded, and can use web components APIs.
    // Next, load element definitions that call `customElements.define`.
    // Note: returning a promise causes the custom elements
    // polyfill to wait until all definitions are loaded and then upgrade
    // the document in one batch, for better performance.
    return loadScript('my-element.js');
  });
</script>

결론

맞춤 요소는 브라우저에서 새 HTML 태그를 정의할 수 있는 새로운 도구와 생성할 수 있습니다. 다른 새 플랫폼과 결합 Shadow DOM 및 <template>과 같은 프리미티브를 구현했으며, 웹 구성요소 그림:

  • 재사용 가능한 구성요소를 만들고 확장하기 위한 교차 브라우저 (웹 표준)
  • 시작하는 데 라이브러리나 프레임워크가 필요하지 않습니다. Vanilla JS/HTML FTW!
  • 익숙한 프로그래밍 모델을 제공합니다. 바로 DOM/CSS/HTML입니다.
  • 다른 새로운 웹 플랫폼 기능 (Shadow DOM, <template>, CSS)과 잘 호환됩니다. 커스텀 속성 등)
  • 브라우저의 DevTools와 긴밀하게 통합됨
  • 기존 접근성 기능 활용