A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://developer.cdn.mozilla.net/ko/docs/Web/API/Web_components/Using_custom_elements below:

사용자 ì •ì˜ 요소 사용하기 - Web API

사용자 정의 요소 사용하기

웹 컴포넌트 표준의 주요 기능 중 하나는 사용자 정의 페이지 기능을 제공하는 길고 중첩된 요소들의 묶음으로 만족하는 것보다는, HTML 페이지에서 기능을 캡슐화하는 사용자 정의 요소를 생성하는 능력입니다. 이 문서는 Custom Elements API의 사용을 소개합니다.

중요 내용 보기

웹 document의 사용자 정의 요소의 컨트롤러는 CustomElementRegistry 객체입니다. 이 객체는 페이지에 사용자 정의 요소를 등록할 수 있게 하고, 어떤 사용자 정의 요소가 등록되었는지 등에 대한 정보를 반환합니다.

페이지에 사용자 정의 요소를 등록하는 방법은 CustomElementRegistry.define() 메서드를 사용하는 것입니다. 이 메서드는 인자로 다음을 취합니다.

예를 들어, 사용자 정의 단어 카운트 요소를 다음과 같이 정의할 수 있습니다.

customElements.define("word-count", WordCount, { extends: "p" });

이 요소는 word-count 라고 불리며, 이것의 클래스 객체는 WordCount 이고, 이것은 <p>요소를 확장합니다.

사용자 정의 요소의 클래스 객체는 표준 ES 2015 class 구문을 사용하여 작성됩니다. 에를 들어, WordCount 는 다음과 같이 구조화될 수 있습니다.

class WordCount extends HTMLParagraphElement {
  constructor() {
    // 항상 super를 생성자에서 먼저 호출합니다
    super();

    // 요소 기능은 여기 작성됩니다

    ...
  }
}

이것은 단순히 간단한 예제이지만, 여기서 할 수 있는 더 많은 것이 있습니다. 클래스 내부에서 특정한 생명 주기 콜백을 정의할 수 있는데, 이 콜백은 요소의 생명 주기의 특정한 지점에서 실행됩니다. 예를 들어, connectedCallback 은 사용자 정의 요소가 문서에 연결된 요소에 추가될 때마다 호출되는 반면, attributeChangedCallback 은 사용자 정의 요소의 특성 중 하나가 추가되거나, 제거되거나, 변경될 때 호출됩니다.

아래의 생명 주기 콜백 사용하기 섹션에서 더 많은 것을 배울 수 있습니다.

두 종류의 사용자 정의 요소가 있습니다.

몇 가지 간단한 예제 살펴보기

이 지점에서, 어떻게 사용자 정의 요소가 생성되는지를 자세히 보여주는 몇 가지 간단한 예제를 살펴봅시다.

독립적인 사용자 정의 요소

독립적인 사용자 정의 요소의 예제를 살펴봅시다. <popup-info-box> (작동 예제도 볼 수 있습니다). 이것은 이미지 아이콘과 텍스트 문자열을 취하고, 아이콘을 페이지에 넣습니다. 아이콘이 포커스되었을 때, 이것은 텍스트를 팝업 정보 박스에 표시하여 추가적인 맥락 내 정보를 제공합니다.

우선, JavaScript 파일에서 PopUpInfo 라는 클래스를 정의하는데, 이 클래스는 포괄적인 HTMLElement 클래스를 확장합니다.

class PopUpInfo extends HTMLElement {
  constructor() {
    // 항상 super를 생성자에서 먼저 호출합니다
    super();

    // 요소 기능을 여기 작성합니다

    ...
  }
}

앞선 코드 스니펫은 클래스에 대한 constructor() 정의를 포함하고 있는데, 이는 항상 super()를 호출함으로써 시작하여 올바른 프로토타입 체인이 확립되도록 합니다.

생성자 내부에서, 클래스의 인스턴스가 인스턴스화되었을 때 요소가 가질 모든 기능을 정의합니다. 이 경우 우리는 shadow root을 사용자 정의 요소에 부착하고, 몇 가지 DOM 조작을 사용하여 요소의 내부 shadow DOM 구조를 생성하는데, 이는 그리고서 shadow root에 부착됩니다. 그리고 마지막으로 몇 가지 CSS를 shadow root에 부착하여 shadow DOM을 꾸밉니다.

// shadow root을 생성합니다
this.attachShadow({ mode: "open" }); // 'this.shadowRoot'을 설정하고 반환합니다

// (중첩된) span 요소들을 생성합니다
const wrapper = document.createElement("span");
wrapper.setAttribute("class", "wrapper");
const icon = wrapper.appendChild(document.createElement("span"));
icon.setAttribute("class", "icon");
icon.setAttribute("tabindex", 0);
// 정의된 특성으로부터의 아이콘 혹은 기본 아이콘을 삽입합니다
const img = icon.appendChild(document.createElement("img"));
img.src = this.hasAttribute("src")
  ? this.getAttribute("src")
  : "img/default.png";

const info = wrapper.appendChild(document.createElement("span"));
info.setAttribute("class", "info");
// 특성의 내용을 취하고 그것을 info span 내부에 넣습니다
info.textContent = this.getAttribute("data-text");

// shadow dom에 적용할 몇 가지 CSS를 생성합니다
const style = document.createElement("style");
style.textContent =
  ".wrapper {" +
  // 간결함을 위해 CSS 생략됨

  // 생성된 요소들을 shadow DOM에 부착합니다
  this.shadowRoot.append(style, wrapper);

마지막으로, CustomElementRegistry 에 사용자 정의 요소를 앞에서 언급된 define() 메서드를 사용해 등록합니다. 매개변수에서 요소의 이름과, 그리고 나서 요소의 기능을 정의하는 클래스명을 명시합니다.

customElements.define("popup-info", PopUpInfo);

이 요소는 이제 페이지에서 사용 가능합니다. HTML 전체에서, 요소를 다음과 같이 사용합니다.

<popup-info
  img="img/alt.png"
  data-text="Your card validation code (CVC)
  is an extra security feature — it is the last 3 or 4 numbers on the
  back of your card."></popup-info>

참고: 전체 JavaScript 소스 코드를 여기서 확인할 수 있습니다.

내부 스타일 대 외부 스타일

상기의 예제에서 <style> 요소가 사용되어 Shadow DOM에 스타일을 적용했으나, 대신 <link> 요소로부터 외부 스타일시트를 참조함으로써 스타일을 적용하는 것도 완벽히 가능합니다.

예를 들자면, popup-info-box-external-stylesheet 예제에서 이 코드를 확인해 보세요 (소스 코드도 볼 수 있습니다).

// 외부 스타일을 shadow dom에 적용하기
const linkElem = document.createElement("link");
linkElem.setAttribute("rel", "stylesheet");
linkElem.setAttribute("href", "style.css");

// 생성된 요소를 shadow dom에 부착하기
shadow.appendChild(linkElem);

<link> 요소는 shadow root의 페인트를 막지 않아, 스타일시트가 로딩되는 동안 스타일되지 않은 내용의 번쩍임 (FOUC, flash of unstyled content) 이 있을 수 있다는 점에 주의하세요.

많은 모던 브라우저들은 공통 노드로부터 복제되었거나 동일한 텍스트를 가지고 있는 <style> 태그에 대한 최적화를 구현하여 스타일 태그가 하나의 백업 스타일시트를 공유할 수 있게 합니다. 이 최적화로 인해 외부 스타일과 내부 스타일의 성능은 비슷할 것입니다.

사용자 정의된 내장 요소

이제 사용자 정의된 요소 예제를 살펴봅시다. expanding-list (작동 예제도 확인해 보세요). 이것은 정렬되지 않은 리스트를 확장/축소 메뉴로 바꿔 줍니다.

우선, 요소의 클래스를 이전과 같은 방식으로 정의합니다.

class ExpandingList extends HTMLUListElement {
  constructor() {
    // 항상 super를 생성자에서 먼저 호출합니다
    super();

    // 요소 기능을 여기 작성합니다

    ...
  }
}

요소 기능을 여기서는 자세히 설명하지 않을 것이지만, 소스 코드를 확인해서 어떻게 작동하는지 발견할 수 있을 것입니다. 여기서의 차이는 이 요소가 HTMLElement가 아니라, HTMLUListElement 인터페이스를 확장한다는 것입니다. 그래서 이 요소는 독립된 요소이기보다는 <ul> 요소의 모든 특성을 가지고 있으며 그 위에 우리가 정의한 기능 또한 가지고 있습니다. 이것이 이 요소를 독립적인 요소보다는 사용자 정의된 내장 요소로 만들어주는 것입니다.

다음으로, 전과 같이 define() 메서드를 사용하여 요소를 등록하나, 이번엔 이 사용자 정의 요소가 어떤 요소를 상속받는지를 나타내는 옵션 객체를 포함합니다.

customElements.define("expanding-list", ExpandingList, { extends: "ul" });

웹 document에서 이 내장 요소를 사용하는 것은 또한 어느 정도 다르게 보입니다.

<ul is="expanding-list">
  ...
</ul>

<ul> 요소를 평범하게 사용하나, is 특성 내부에 사용자 정의 요소의 이름을 명시합니다.

참고: 전체 JavaScript 소스 코드를 확인해볼 수 있습니다.

생명 주기 콜백 사용하기

몇 가지 다른 콜백을 사용자 정의 요소의 클래스 정의 내부에 정의할 수 있는데, 이 콜백들은 요소의 생명 주기의 각기 다른 지점에서 발생됩니다.

이것들의 사용례를 봅시다. 아래의 코드는 life-cycle-callbacks 예제에서 취해졌습니다 (작동 예제도 볼 수 있습니다). 이것은 페이지에 고정된 크기의 색이 칠해진 사각형을 생성하는 작은 예제입니다. 사용자 정의 요소는 다음과 같이 생겼습니다.

<custom-square l="100" c="red"></custom-square>

클래스 생성자는 정말로 간단합니다. shadow DOM을 요소에 부착하고, 빈 <div> 와 <style> 요소를 shadow root에 부착합니다.

const shadow = this.attachShadow({ mode: "open" });

const div = document.createElement("div");
const style = document.createElement("style");
shadow.appendChild(style);
shadow.appendChild(div);

이 예제에서의 핵심 함수는 updateStyle() 입니다. 이 함수는 요소를 취하고, 요소의 shadow root을 얻고, shadow root의 <style> 요소를 찾고, width, height, background-color를 스타일에 추가합니다.

function updateStyle(elem) {
  const shadow = elem.shadowRoot;
  shadow.querySelector("style").textContent = `
    div {
      width: ${elem.getAttribute("l")}px;
      height: ${elem.getAttribute("l")}px;
      background-color: ${elem.getAttribute("c")};
    }
  `;
}

실제 갱신은 모두 생명 주기 콜백에 의해 다뤄지는데, 이 콜백들은 클래스 정의 내부에 메서드로 위치합니다. connectedCallback() 은 요소가 DOM에 추가될 때마다 실행됩니다. 여기서 updateStyle() 함수가 실행되어 사각형이 이것의 특성에 정의된 대로 꾸며지도록 합니다.

connectedCallback() {
  console.log('Custom square element added to page.');
  updateStyle(this);
}

disconnectedCallback() 과 adoptedCallback() 콜백은 콘솔에 간단한 메시지를 로그하여 언제 요소가 DOM에서 제거되었는지, 혹은 다른 페이지로 이동되었는지를 알립니다.

disconnectedCallback() {
  console.log('Custom square element removed from page.');
}

adoptedCallback() {
  console.log('Custom square element moved to new page.');
}

attributeChangedCallback() 은 요소의 특성 중 하나가 어떠한 방식으로 변경될 때마다 실행됩니다. 이 콜백의 매개변수에서 볼 수 있다시피, 특성의 이름, 이전 값, 새로운 값을 보고 특성의 변경 사항에 개별적으로 대응하는 게 가능합니다. 그러나, 이번 경우에는 개별적으로 대응하지 않고, 사각형의 스타일이 새로운 값에 따라 갱신될 수 있도록 단순히 updateStyle() 함수를 다시 호출합니다.

attributeChangedCallback(name, oldValue, newValue) {
  console.log('Custom square element attributes changed.');
  updateStyle(this);
}

attributeChangedCallback() 콜백이 특성이 변경되었을 때 발생되기 하기 위해서는, 해당 특성을 관찰해야만 합니다. 이 작업은 static get observedAttributes() 메서드를 사용자 정의 요소 클래스 내부에 명시함으로써 이루어집니다. 이 메서드는 관찰하기를 원하는 특성들의 이름을 포함하는 배열을 return 해야 합니다.

static get observedAttributes() { return ['c', 'l']; }

이 예제에서 이 메서드는 생성자의 바로 위에 위치해 있습니다.

참고: 전체 JavaScript 소스 코드를 확인해 보세요.

트랜스파일러 대 클래스

ES2015 class는 레거시 브라우저를 목표로 하는 Babel 6 또는 TypeScript 에서 신뢰할만하게 트랜스파일될 수 없다는 점에 주의하세요. Babel 7을 사용하거나 Babel 6에 대해서 babel-plugin-transform-builtin-classes를 사용할 수 있고, 레거시 대신에 TypeScript의 ES2015를 목표로 할 수 있습니다.

라이브러리

사용자 정의 요소를 생성할 때 추상화의 단계를 올리는 것을 목표로 하는 웹 컴포넌트를 기반으로 하는 몇 가지의 라이브러리들이 있습니다. 이러한 라이브러리에는 FASTElement, snuggsi, X-Tag, Slim.js, Lit, Smart, Stencil, hyperHTML-Element, DataFormsJS, Custom-Element-Builder가 있습니다.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4