Elemen khusus memungkinkan pengembang web untuk menetapkan tag HTML baru, memperluas yang sudah ada, dan membuat komponen web yang dapat digunakan kembali.
Dengan Elemen Kustom, developer web dapat membuat tag HTML baru, meningkatkan tag HTML yang ada, atau memperluas komponen yang ditulis oleh developer lain. API adalah dasar dari komponen web. Library ini menghadirkan cara berbasis standar web untuk membuat komponen yang dapat digunakan kembali dengan hanya menggunakan JS/HTML/CSS biasa. Hasilnya adalah lebih sedikit kode, kode modular, dan lebih dapat digunakan kembali di aplikasi kami.
Pengantar
Browser memberi kita alat yang sangat baik untuk menyusun aplikasi web. yang disebut HTML. Anda mungkin pernah mendengarnya! Ini deklaratif, portabel, didukung dengan baik, dan mudah digunakan. Sehebat HTML, kosakata dan ekstensibilitasnya terbatas. Standar hidup HTML selalu tidak memiliki cara untuk secara otomatis mengaitkan perilaku JS dengan markup Anda... hingga sekarang.
Elemen kustom adalah solusi untuk memodernisasi HTML, mengisi bagian yang hilang, dan memaketkan struktur dengan perilaku. Jika HTML tidak memberikan solusi untuk suatu masalah, kita dapat membuat elemen khusus. Elemen kustom mengajarkan trik baru ke browser sekaligus mempertahankan manfaat HTML.
Mendefinisikan elemen baru
Untuk mendefinisikan elemen HTML baru, kita membutuhkan kemampuan JavaScript!
Global customElements
digunakan untuk menentukan elemen kustom dan mengajarkan tag baru kepada browser. Panggil customElements.define()
dengan nama tag yang ingin Anda buat dan class
JavaScript yang memperluas HTMLElement
dasar.
Contoh - menentukan panel panel samping seluler, <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 {...});
Contoh penggunaan:
<app-drawer></app-drawer>
Penting untuk diingat bahwa menggunakan elemen kustom tidak berbeda dengan
menggunakan <div>
atau elemen lainnya. Instance dapat dideklarasikan di halaman, dibuat secara dinamis di JavaScript, pemroses peristiwa dapat dilampirkan, dll. Baca terus untuk mengetahui contoh lainnya.
Menentukan JavaScript API elemen
Fungsi elemen kustom ditentukan menggunakan class
ES2015 yang memperluas HTMLElement
. Memperluas HTMLElement
akan memastikan elemen kustom mewarisi seluruh DOM API, dan setiap properti/metode yang Anda tambahkan ke class akan menjadi bagian dari antarmuka DOM elemen. Pada dasarnya, gunakan class tersebut untuk membuat JavaScript API publik untuk tag Anda.
Contoh - menentukan antarmuka DOM <app-drawer>
:
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);
Dalam contoh ini, kita membuat panel samping yang memiliki properti open
, properti disabled
, dan metode toggleDrawer()
. Atribut ini juga mencerminkan properti sebagai atribut HTML.
Salah satu fitur menarik dari elemen khusus adalah this
di dalam definisi class
merujuk pada elemen DOM itu sendiri yaitu instance class. Dalam
contoh kita, this
mengacu pada <app-drawer>
. Ini adalah cara elemen menambahkan pemroses click
ke dirinya sendiri. Dan Anda tidak dibatasi pada pemroses peristiwa.
Seluruh DOM API tersedia di dalam kode elemen. Gunakan this
untuk mengakses properti elemen, memeriksa turunannya (this.children
), node kueri (this.querySelectorAll('.items')
), dll.
Aturan mengenai pembuatan elemen khusus
- Nama elemen kustom harus berisi tanda hubung (-). Jadi,
<x-tags>
,<my-element>
, dan<my-awesome-app>
adalah nama yang valid, sedangkan<tabs>
dan<foo_bar>
tidak. Persyaratan ini dimaksudkan agar parser HTML dapat membedakan elemen kustom dari elemen biasa. Kode ini juga memastikan kompatibilitas dengan penerusan saat tag baru ditambahkan ke HTML. - Anda tidak dapat mendaftarkan tag yang sama lebih dari sekali. Jika dilakukan,
akan menampilkan
DOMException
. Setelah Anda memberi tahu browser tentang tag baru, selesai. Tidak ada pengembalian. - Elemen kustom tidak dapat menutup sendiri karena HTML hanya mengizinkan beberapa elemen untuk menutup sendiri. Selalu tulis tag penutup (
<app-drawer></app-drawer>
).
Reaksi elemen kustom
Elemen kustom dapat menentukan hook siklus proses khusus untuk menjalankan kode selama waktu menarik dari keberadaannya. Ini disebut reaksi elemen kustom.
Nama | Ditelepon saat |
---|---|
constructor |
Instance elemen
dibuat atau diupgrade. Berguna untuk menginisialisasi status, menyiapkan pemroses peristiwa, atau membuat dom bayangan.
Lihat
spesifikasi
untuk mengetahui batasan terkait hal yang dapat Anda lakukan di constructor .
|
connectedCallback |
Dipanggil setiap kali elemen disisipkan ke dalam DOM. Berguna untuk menjalankan kode penyiapan, seperti mengambil resource atau rendering. Umumnya, Anda harus mencoba menunda pekerjaan hingga waktu ini. |
disconnectedCallback |
Dipanggil setiap kali elemen dihapus dari DOM. Berguna untuk menjalankan kode pembersihan. |
attributeChangedCallback(attrName, oldVal, newVal) |
Dipanggil saat atribut yang diamati telah ditambahkan, dihapus, diperbarui, atau diganti. Juga dipanggil untuk nilai awal saat elemen dibuat oleh parser, atau diupgrade. Catatan: hanya atribut yang tercantum dalam properti observedAttributes yang akan menerima callback ini.
|
adoptedCallback |
Elemen kustom telah dipindahkan ke document baru (misalnya seseorang yang bernama document.adoptNode(el) ).
|
Callback reaksi bersifat sinkron. Jika seseorang memanggil el.setAttribute()
pada elemen Anda, browser akan segera memanggil attributeChangedCallback()
.
Demikian pula, Anda akan menerima disconnectedCallback()
langsung setelah elemen dihapus dari DOM (misalnya, pengguna memanggil el.remove()
).
Contoh: menambahkan reaksi elemen kustom ke <app-drawer>
:
class AppDrawer extends HTMLElement {
constructor() {
super(); // always call super() first in the constructor.
// ...
}
connectedCallback() {
// ...
}
disconnectedCallback() {
// ...
}
attributeChangedCallback(attrName, oldVal, newVal) {
// ...
}
}
Definisikan reaksi jika/jika diperlukan. Jika elemen Anda cukup kompleks
dan membuka koneksi ke IndexedDB di connectedCallback()
, lakukan pekerjaan pembersihan
yang diperlukan di disconnectedCallback()
. Tapi hati-hati! Dalam situasi apa pun, Anda tidak bisa mengandalkan
elemen yang dihapus dari DOM. Misalnya,
disconnectedCallback()
tidak akan pernah dipanggil jika pengguna menutup tab.
Properti dan atribut
Merefleksikan properti ke atribut
Sangatlah umum bagi properti HTML untuk mencerminkan nilainya kembali ke DOM sebagai
atribut HTML. Misalnya, saat nilai hidden
atau id
diubah di JS:
div.id = 'my-id';
div.hidden = true;
nilai-nilai tersebut diterapkan ke live DOM sebagai atribut:
<div id="my-id" hidden>
Hal ini disebut "merefleksikan properti ke atribut". Hampir setiap properti di HTML melakukan hal ini. Mengapa? Atribut juga berguna untuk mengonfigurasi elemen secara deklaratif, dan API tertentu seperti aksesibilitas dan pemilih CSS bergantung pada atribut agar berfungsi.
Merefleksikan properti berguna di mana pun Anda ingin menjaga representasi DOM elemen tetap sinkron dengan status JavaScript-nya. Salah satu alasan Anda mungkin ingin menampilkan properti adalah agar gaya yang ditentukan pengguna diterapkan saat status JS berubah.
Ingat kembali <app-drawer>
kita. Konsumen komponen ini mungkin ingin memudarnya
dan/atau mencegah interaksi pengguna saat dinonaktifkan:
app-drawer[disabled] {
opacity: 0.5;
pointer-events: none;
}
Saat properti disabled
diubah di JS, kita ingin atribut tersebut
ditambahkan ke DOM agar pemilih pengguna cocok. Elemen ini dapat menyediakan
perilaku tersebut dengan merefleksikan nilai ke atribut dengan nama yang sama:
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();
}
Mengamati perubahan pada atribut
Atribut HTML adalah cara yang mudah bagi pengguna untuk mendeklarasikan status awal:
<app-drawer open disabled></app-drawer>
Elemen dapat bereaksi terhadap perubahan atribut dengan menentukan
attributeChangedCallback
. Browser akan memanggil metode ini untuk setiap perubahan
pada atribut yang tercantum dalam array 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.
}
}
Dalam contoh, kita menetapkan atribut tambahan pada <app-drawer>
saat atribut disabled
diubah. Meskipun kita tidak melakukannya di sini, Anda juga dapat menggunakan attributeChangedCallback
untuk menjaga properti JS tetap sinkron dengan atributnya.
Upgrade elemen
HTML yang disempurnakan secara progresif
Kita telah mempelajari bahwa elemen kustom ditentukan dengan memanggil
customElements.define()
. Namun ini tidak berarti Anda harus mendefinisikan + mendaftarkan
elemen khusus sekaligus.
Elemen kustom dapat digunakan sebelum definisinya didaftarkan.
{i>Progressive enhancement <i}adalah fitur elemen khusus. Dengan kata lain, Anda dapat
mendeklarasikan sekumpulan elemen <app-drawer>
di halaman dan tidak akan pernah memanggil
customElements.define('app-drawer', ...)
hingga nanti. Hal ini karena
browser memperlakukan elemen kustom potensial secara berbeda berkat tag
yang tidak diketahui. Proses pemanggilan define()
dan pemberian elemen
yang ada dengan definisi class disebut "upgrade elemen".
Untuk mengetahui kapan nama tag ditentukan, Anda dapat menggunakan
window.customElements.whenDefined()
. Metode ini menampilkan Promise yang akan ditetapkan saat elemen telah ditentukan.
customElements.whenDefined('app-drawer').then(() => {
console.log('app-drawer defined');
});
Contoh - menunda pekerjaan hingga kumpulan elemen turunan diupgrade
<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.
});
Konten yang ditentukan elemen
Elemen khusus dapat mengelola kontennya sendiri menggunakan DOM API di dalam kode elemen. Reaksi sangat berguna dalam hal ini.
Contoh - buat elemen dengan beberapa HTML default:
customElements.define('x-foo-with-markup', class extends HTMLElement {
connectedCallback() {
this.innerHTML = "<b>I'm an x-foo-with-markup!</b>";
}
// ...
});
Mendeklarasikan tag ini akan menghasilkan:
<x-foo-with-markup>
<b>I'm an x-foo-with-markup!</b>
</x-foo-with-markup>
// TODO: DevSite - Contoh kode dihapus karena menggunakan pengendali peristiwa inline
Membuat elemen yang menggunakan Shadow DOM
Shadow DOM menyediakan cara bagi elemen untuk memiliki, merender, dan menata gaya suatu bagian DOM yang terpisah dari bagian halaman lainnya. Anda bahkan dapat menyembunyikan seluruh aplikasi dalam satu tag:
<!-- chat-app's implementation details are hidden away in Shadow DOM. -->
<chat-app></chat-app>
Untuk menggunakan Shadow DOM dalam elemen kustom, panggil this.attachShadow
di dalam
constructor
Anda:
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));
}
// ...
});
Contoh penggunaan:
<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>
Teks kustom pengguna
// TODO: DevSite - Contoh kode dihapus karena menggunakan pengendali peristiwa inline
Membuat elemen dari <template>
Untuk yang tidak dikenal, elemen <template>
memungkinkan Anda mendeklarasikan fragmen DOM yang diuraikan, tidak aktif saat pemuatan halaman, dan dapat diaktifkan nanti saat runtime. Ini adalah primitif API lain dalam kelompok
komponen web. Template adalah placeholder yang ideal untuk mendeklarasikan
struktur elemen kustom.
Contoh: mendaftarkan elemen dengan konten Shadow DOM yang dibuat dari <template>
:
<template id="x-foo-from-template">
<style>
p { color: green; }
</style>
<p>I'm in Shadow DOM. My markup was stamped from a <template>.</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>
Beberapa baris kode ini punya kekuatan yang luar biasa. Mari kita pahami hal-hal penting yang terjadi:
- Kita menentukan elemen baru di HTML:
<x-foo-from-template>
- Shadow DOM elemen dibuat dari
<template>
- DOM elemen bersifat lokal untuk elemen berkat Shadow DOM
- CSS internal elemen dicakup ke elemen berkat Shadow DOM
Saya berada di Shadow DOM. Markup saya diberi stempel dari <template>.
// TODO: DevSite - Contoh kode dihapus karena menggunakan pengendali peristiwa inline
Menata gaya elemen kustom
Meskipun elemen Anda menentukan gayanya sendiri menggunakan Shadow DOM, pengguna dapat menata gaya elemen kustom Anda dari halaman mereka. Ini disebut "gaya yang ditentukan pengguna".
<!-- 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>
Anda mungkin bertanya-tanya cara kerja kekhususan CSS jika elemen memiliki gaya yang ditentukan dalam Shadow DOM. Dalam hal kekhususan, gaya pengguna lebih unggul. Gaya visual tersebut akan selalu menggantikan gaya visual yang ditentukan elemen. Lihat bagian Membuat elemen yang menggunakan Shadow DOM.
Pra-gaya pada elemen yang tidak terdaftar
Sebelum elemen diupgrade, Anda dapat menargetkannya di CSS menggunakan
class pseudo :defined
. Hal ini berguna untuk menata gaya komponen terlebih dahulu. Misalnya, Anda mungkin ingin mencegah tata letak atau FOUC visual lainnya dengan menyembunyikan komponen yang tidak ditentukan
dan memudarnya saat komponen tersebut ditentukan.
Contoh - sembunyikan <app-drawer>
sebelum ditentukan:
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;
}
Setelah <app-drawer>
ditentukan, pemilih (app-drawer:not(:defined)
)
tidak lagi cocok.
Memperluas elemen
Custom Elements API berguna untuk membuat elemen HTML baru, namun juga berguna untuk memperluas elemen khusus lainnya atau bahkan HTML bawaan browser.
Memperluas elemen kustom
Memperluas elemen kustom lain dilakukan dengan memperluas definisi class-nya.
Contoh - buat <fancy-app-drawer>
yang memperluas <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);
Memperluas elemen HTML native
Misalnya Anda ingin membuat <button>
yang lebih mewah. Daripada mereplikasi perilaku dan fungsi <button>
, opsi yang lebih baik adalah meningkatkan kualitas elemen yang ada secara bertahap menggunakan elemen kustom.
Elemen bawaan yang disesuaikan adalah elemen kustom yang memperluas salah satu tag HTML bawaan browser. Manfaat utama memperluas elemen yang sudah ada adalah mendapatkan semua fiturnya (properti DOM, metode, aksesibilitas). Tidak ada cara yang lebih baik untuk menulis progressive web app selain meningkatkan kualitas elemen HTML yang sudah ada secara progresif.
Untuk memperluas elemen, Anda harus membuat definisi class yang mewarisi dari antarmuka DOM yang benar. Misalnya, elemen kustom yang memperluas
<button>
harus mewarisi dari HTMLButtonElement
, bukan HTMLElement
.
Demikian pula, elemen yang memperluas <img>
harus memperluas HTMLImageElement
.
Contoh - memperluas <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'});
Perhatikan bahwa panggilan ke define()
sedikit berubah saat memperluas elemen
native. Parameter ketiga yang diperlukan memberi tahu browser tag mana yang akan Anda perluas. Hal ini diperlukan karena banyak tag HTML menggunakan antarmuka DOM yang sama. <section>
, <address>
, dan <em>
(di antaranya) semuanya berbagi
HTMLElement
; <q>
dan <blockquote>
berbagi HTMLQuoteElement
; dll...
Dengan menentukan {extends: 'blockquote'}
, browser akan mengetahui bahwa Anda sedang membuat
<blockquote>
suplai, bukan <q>
. Lihat spesifikasi HTML untuk mengetahui daftar lengkap antarmuka DOM HTML.
Konsumen elemen bawaan yang disesuaikan dapat menggunakannya dalam beberapa cara. Mereka dapat
mendeklarasikan dengan menambahkan atribut is=""
pada tag native:
<!-- This <button> is a fancy button. -->
<button is="fancy-button" disabled>Fancy button!</button>
membuat instance di 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);
atau gunakan operator new
:
let button = new FancyButton();
button.textContent = 'Fancy button!';
button.disabled = true;
Berikut ini contoh lain yang memperluas <img>
.
Contoh - memperluas <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'});
Pengguna mendeklarasikan komponen ini sebagai:
<!-- This <img> is a bigger img. -->
<img is="bigger-img" width="15" height="20">
atau buat instance di 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);
Detail lain-lain
Elemen tidak diketahui vs. elemen kustom yang tidak ditentukan
HTML longgar dan fleksibel untuk digunakan. Misalnya, deklarasikan
<randomtagthatdoesntexist>
pada halaman dan browser akan benar-benar
menerimanya. Mengapa tag non-standar berfungsi? Jawabannya adalah spesifikasi
HTML
memungkinkannya. Elemen yang tidak ditentukan oleh spesifikasi akan diurai sebagai HTMLUnknownElement
.
Hal yang sama tidak berlaku untuk elemen khusus. Elemen kustom yang potensial akan diuraikan sebagai HTMLElement
jika dibuat dengan nama yang valid (menyertakan "-"). Anda dapat memeriksanya di browser yang mendukung elemen kustom. Aktifkan Konsol:
Ctrl+Shift+J (atau Cmd+Opt+J di Mac) dan tempelkan di
baris kode berikut:
// "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
Referensi API
customElements
global menentukan metode yang berguna untuk menangani elemen
kustom.
define(tagName, constructor, options)
Mendefinisikan elemen kustom baru di browser.
Contoh
customElements.define('my-app', class extends HTMLElement { ... });
customElements.define(
'fancy-button', class extends HTMLButtonElement { ... }, {extends: 'button'});
get(tagName)
Dengan mempertimbangkan nama tag elemen kustom yang valid, menampilkan konstruktor elemen.
Menampilkan undefined
jika tidak ada definisi elemen yang terdaftar.
Contoh
let Drawer = customElements.get('app-drawer');
let drawer = new Drawer();
whenDefined(tagName)
Menampilkan Promise yang me-resolve saat elemen kustom ditentukan. Jika elemen sudah didefinisikan, segera selesaikan. Menolak jika nama tag bukan nama elemen kustom yang valid.
Contoh
customElements.whenDefined('app-drawer').then(() => {
console.log('ready!');
});
Histori dan dukungan browser
Jika Anda telah mengikuti komponen web selama beberapa tahun terakhir, Anda akan
mengetahui bahwa Chrome 36+ menerapkan versi Custom Elements API yang menggunakan
document.registerElement()
, bukan customElements.define()
. Versi tersebut kini
dianggap sebagai versi standar yang tidak digunakan lagi, yang disebut v0.
customElements.define()
adalah popularitas baru dan apa yang mulai diterapkan oleh
vendor browser. Alat ini disebut Custom Elements v1.
Jika Anda tertarik dengan spesifikasi v0 lama, lihat artikel html5Rock.
Dukungan browser
Chrome 54 (status), Safari 10.1 (status), dan Firefox 63 (status) memiliki Custom Elements v1. Edge telah memulai pengembangan.
Untuk mendeteksi elemen kustom, periksa keberadaan
window.customElements
:
const supportsCustomElementsV1 = 'customElements' in window;
Isi Ulang
Sebelum dukungan browser tersedia secara luas, ada polyfill mandiri yang tersedia untuk Custom Elements v1. Namun, sebaiknya gunakan loader webcomponents.js untuk memuat polyfill komponen web secara optimal. Loader menggunakan deteksi fitur untuk memuat hanya pollyfills yang diperlukan oleh browser secara asinkron.
Instal:
npm install --save @webcomponents/webcomponentsjs
Penggunaan:
<!-- 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>
Kesimpulan
Elemen khusus memberi kita alat baru untuk menentukan tag HTML baru di browser dan membuat komponen yang dapat digunakan kembali. Kombinasikan keduanya dengan primitif platform baru
lainnya seperti Shadow DOM dan <template>
, dan kita mulai mewujudkan gambaran
utama dari Komponen Web:
- Lintas browser (standar web) untuk membuat dan memperluas komponen yang dapat digunakan kembali.
- Tidak memerlukan library atau framework untuk memulai. Vanila JS/HTML FTW!
- Menyediakan model pemrograman yang familier. Cuma DOM/CSS/HTML.
- Berfungsi baik dengan fitur platform web baru lainnya (Shadow DOM,
<template>
, properti kustom CSS, dll.) - Terintegrasi erat dengan DevTools browser.
- Manfaatkan fitur aksesibilitas yang ada.