Dengan elemen khusus, developer web dapat menentukan 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, menambah tag HTML yang sudah ada, atau memperluas komponen yang dimiliki pengembang lain ditulis. API merupakan fondasi dari komponen. Ini menghadirkan web berbasis standar untuk membuat komponen yang dapat digunakan kembali dengan menggunakan tidak lebih dari JS/HTML/CSS biasa. Hasilnya adalah lebih sedikit kode, kode modular, dan lebih dapat digunakan kembali di aplikasi kita.
Pengantar
{i>Browser<i} memberi kita alat yang sangat baik untuk menyusun aplikasi web. Penting disebut HTML. Anda mungkin pernah mendengarnya! Perangkat ini deklaratif, portabel, didukung, dan mudah digunakan. Seperti HTML, kosakata, dan ekstensibilitas terbatas. HTML yang hidup standar selalu tidak memiliki cara untuk secara otomatis mengaitkan perilaku JS dengan markup Anda... hingga sekarang.
Elemen kustom adalah jawaban untuk memodernisasi HTML dengan mengisi bagian, dan memaketkan struktur dengan perilaku. Jika HTML tidak menyediakan solusi untuk suatu masalah, kita dapat membuat elemen khusus yang dapat melakukannya. Khusus yang baru mengajarkan trik baru pada browser sekaligus mempertahankan manfaat HTML.
Mendefinisikan elemen baru
Untuk menentukan elemen HTML baru, kita memerlukan kemampuan JavaScript!
customElements
global digunakan untuk menentukan elemen khusus dan mengajarkan
browser tentang tag baru. 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 khusus tidak berbeda dengan
menggunakan <div>
atau elemen lainnya. {i>Instance <i}dapat dideklarasikan di laman,
dibuat secara dinamis di JavaScript, pemroses peristiwa dapat dilampirkan, dll. Keep
membaca untuk contoh lainnya.
Menentukan JavaScript API elemen
Fungsi elemen kustom ditentukan dengan menggunakan ES2015
class
yang memperluas HTMLElement
. Memperluas HTMLElement
memastikan elemen kustom
mewarisi seluruh DOM API dan berarti setiap properti/metode yang Anda tambahkan
menjadi bagian dari antarmuka DOM elemen. Pada dasarnya, gunakan class untuk
buat 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
, disabled
properti, dan metode toggleDrawer()
. Hal ini juga mencerminkan properti sebagai HTML
atribut.
Fitur rapi dari elemen kustom adalah this
di dalam definisi class
merujuk ke elemen DOM itu sendiri, yaitu instance class. Di
contoh, this
merujuk pada <app-drawer>
. Ini (Tema) adalah bagaimana elemen itu bisa
memasang 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, periksa 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 agar parser HTML bisa membedakan elemen khusus dari elemen biasa. Hal ini juga memastikan penerusan kompatibilitas saat tag baru ditambahkan ke HTML. - Anda tidak dapat mendaftarkan tag yang sama lebih dari sekali. Mencoba melakukannya akan
tampilkan
DOMException
. Setelah memberi tahu browser tentang tag baru, anotasi. Tidak dapat dikembalikan. - Elemen khusus tidak dapat menutup sendiri karena HTML hanya mengizinkan beberapa
yang berbeda
tertutup sendiri. Selalu tulis tag penutup
(
<app-drawer></app-drawer>
).
Reaksi elemen kustom
Elemen kustom dapat menentukan {i>hook<i} siklus proses khusus untuk menjalankan kode selama masa-masa yang menarik. Ini disebut elemen khusus reaksi.
Nama | Dipanggil saat |
---|---|
constructor |
Sebuah instance dari elemen ini
dibuat atau diupgrade. Berguna untuk menginisialisasi
status, menyiapkan pemroses peristiwa, atau
membuat shadow dom.
Lihat
spec
untuk batasan tentang hal-hal yang dapat Anda lakukan di constructor .
|
connectedCallback |
Dipanggil setiap kali disisipkan ke dalam DOM. Berguna untuk menjalankan kode penyiapan, seperti untuk mengambil resource atau rendering. Umumnya, Anda harus mencoba untuk menunda pekerjaan sampai sekarang. |
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 disebut untuk nilai awal
saat elemen dibuat oleh parser, atau
diupgrade. Catatan: saja
atribut yang tercantum dalam properti observedAttributes akan
menerima callback ini.
|
adoptedCallback |
Tujuan
elemen kustom telah dipindahkan ke document baru (mis.
seseorang bernama document.adoptNode(el) ).
|
Callback reaksi bersifat sinkron. Jika seseorang menelepon el.setAttribute()
pada elemen Anda, browser akan segera memanggil attributeChangedCallback()
.
Demikian pula, Anda akan menerima disconnectedCallback()
tepat 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) {
// ...
}
}
Tentukan reaksi jika/jika memang masuk akal. Jika elemen Anda cukup kompleks
dan membuka koneksi ke IndexedDB di connectedCallback()
, lakukan hal yang diperlukan
pembersihan data di disconnectedCallback()
. Tapi hati-hati! Anda tidak dapat mengandalkan
dihapus dari DOM dalam segala keadaan. Misalnya,
disconnectedCallback()
tidak akan pernah dipanggil jika pengguna menutup tab.
Properti dan atribut
Mencerminkan properti ke atribut
Umumnya properti HTML mencerminkan nilainya ke DOM sebagai
atribut HTML. Misalnya, saat nilai hidden
atau id
diubah di
JS:
div.id = 'my-id';
div.hidden = true;
nilai tersebut diterapkan ke DOM langsung sebagai atribut:
<div id="my-id" hidden>
Hal ini disebut "merefleksikan sifat-sifat untuk atribut". Hampir setiap properti di HTML melakukan hal ini. Mengapa? Atribut juga berguna untuk mengonfigurasi elemen secara deklaratif dan API tertentu seperti aksesibilitas dan CSS pemilih mengandalkan atribut itu agar berfungsi.
Merefleksikan properti berguna di mana pun Anda ingin mempertahankan DOM elemen yang disinkronkan dengan status JavaScript-nya. Salah satu alasan Anda mungkin ingin mencerminkan properti sehingga gaya visual 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 sehingga pemilih pengguna cocok. Elemen ini dapat memberikan
perilaku dengan mencerminkan nilai ke atribut bernama 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
ke 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 ini, kita menetapkan atribut tambahan pada <app-drawer>
saat
Atribut disabled
diubah. Meskipun kami tidak melakukannya
di sini, Anda bisa
juga menggunakan attributeChangedCallback
untuk menjaga properti JS tetap sinkron dengan
.
Upgrade elemen
HTML yang disempurnakan secara progresif
Kita telah mempelajari bahwa elemen kustom ditentukan dengan memanggil
customElements.define()
. Namun bukan berarti Anda harus menentukan + mendaftarkan
elemen kustom sekaligus.
Elemen kustom dapat digunakan sebelum definisinya didaftarkan.
{i>Progressive enhancement <i}adalah fitur elemen kustom. Dengan kata lain, Anda bisa
deklarasikan sekelompok elemen <app-drawer>
di halaman dan jangan pernah memanggil
customElements.define('app-drawer', ...)
sampai beberapa saat lagi. Hal ini karena
browser memperlakukan elemen khusus potensial secara berbeda karena
tag. Proses memanggil define()
dan memberikan domain yang sudah ada
dengan definisi kelas disebut "upgrade elemen".
Untuk mengetahui kapan nama tag menjadi ditentukan, Anda dapat menggunakan
window.customElements.whenDefined()
. Metode ini mengembalikan Promise yang akan di-resolve saat
menjadi sudah terdefinisi.
customElements.whenDefined('app-drawer').then(() => {
console.log('app-drawer defined');
});
Contoh - tunda 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 oleh elemen
Elemen khusus bisa mengelola kontennya sendiri menggunakan DOM API yang ada di dalamnya kode elemen. Reaksi 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 potongan DOM yang terpisah dari bagian halaman lainnya. Yah, Anda bahkan bisa menyembunyikan sebuah keseluruhan aplikasi dalam satu tag:
<!-- chat-app's implementation details are hidden away in Shadow DOM. -->
<chat-app></chat-app>
Untuk menggunakan Shadow DOM di elemen kustom, panggil this.attachShadow
di dalam
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));
}
// ...
});
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>
Bagi yang belum memahami, <template>
elemen
memungkinkan Anda mendeklarasikan fragmen DOM yang diuraikan, inert saat pemuatan halaman, dan
dapat diaktifkan nanti saat runtime. Ini adalah primitif API lainnya di web
kelompok komponen. Template adalah placeholder yang ideal untuk mendeklarasikan
elemen kustom.
Contoh: mendaftarkan elemen dengan konten DOM Bayangan 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 sangat menarik. Mari kita pahami hal-hal penting yang terjadi pada:
- Kita menentukan elemen baru dalam HTML:
<x-foo-from-template>
- Shadow DOM elemen dibuat dari
<template>
- DOM elemen bersifat lokal untuk elemen berkat Shadow DOM
- CSS internal elemen tercakup 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
Bahkan jika elemen Anda menentukan gayanya sendiri menggunakan Shadow DOM, pengguna bisa 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 bagaimana kekhususan CSS bekerja jika elemen tersebut memiliki gaya yang ditentukan dalam Shadow DOM. Dalam hal kekhususan, gaya penggunalah yang menang. Mereka akan selalu mengganti gaya visual yang ditentukan elemen. Lihat bagian tentang Membuat elemen yang menggunakan Shadow DOM.
Pra-gaya visual elemen yang tidak terdaftar
Sebelum elemen diupgrade, Anda dapat menargetkannya di CSS menggunakan
Class semu :defined
. Hal ini berguna untuk pra-gaya pada komponen. Sebagai
misalnya, Anda mungkin ingin mencegah tata letak atau FOUC visual lainnya dengan menyembunyikan
dan menghilangkannya ketika
komponen-komponen itu ditetapkan.
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)
)
yang tidak cocok lagi.
Memperluas elemen
Custom Elements API berguna untuk membuat elemen HTML baru, tetapi juga berguna untuk memperluas elemen khusus lain 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 bagus. Alih-alih mereplikasi
perilaku dan fungsi <button>
, opsi yang lebih baik adalah secara progresif
meningkatkan elemen yang ada menggunakan elemen khusus.
Elemen bawaan yang disesuaikan adalah elemen khusus yang memperluas salah satu tag HTML bawaan browser. Manfaat utama dari memperluas jaringan adalah untuk mendapatkan semua fiturnya (properti DOM, metode, aksesibilitas). Tidak ada cara yang lebih baik untuk menulis progressive web app daripada secara progresif menyempurnakan HTML yang sudah ada yang penting.
Untuk memperluas elemen, Anda harus membuat definisi class yang mewarisi
dari antarmuka DOM yang benar. Misalnya, elemen khusus 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 native
. Parameter ketiga yang diperlukan memberi tahu browser tentang tag
memperluas. Ini diperlukan karena banyak tag HTML menggunakan DOM yang sama
dalam antarmuka berbasis web
yang sederhana. <section>
, <address>
, dan <em>
(antara lain) sama-sama berbagi
HTMLElement
; baik <q>
dan <blockquote>
berbagi HTMLQuoteElement
; dll...
Menentukan {extends: 'blockquote'}
akan memberi tahu browser bahwa Anda membuat
<blockquote>
yang ditingkatkan, bukan <q>
. Lihat HTML
spec
untuk mengetahui daftar lengkap antarmuka DOM HTML.
Konsumen elemen bawaan yang disesuaikan dapat menggunakannya dalam beberapa cara. Mereka dapat
deklarasikan 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 adalah 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 membuat 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 lainnya
Elemen tidak diketahui vs. elemen kustom yang belum ditentukan
HTML tolong dan fleksibel untuk digunakan. Misalnya, deklarasikan
<randomtagthatdoesntexist>
di halaman dan browser sangat puas
menerimanya. Mengapa tag non-standar berfungsi? Jawabannya adalah model HTML
spesifikasi
mengizinkannya. Elemen yang tidak ditentukan oleh spesifikasi akan diurai sebagai
HTMLUnknownElement
.
Hal yang sama tidak berlaku untuk elemen khusus. Elemen kustom yang potensial diuraikan
sebagai HTMLElement
jika dibuat dengan nama yang valid (menyertakan "-"). Anda
dapat memeriksanya di {i>browser<i} yang mendukung elemen khusus. Buka Konsol:
Ctrl+Shift+J (atau Cmd+Opt+J di Mac) dan tempelkan di bagian
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
yang kurang penting.
define(tagName, constructor, options)
Mendefinisikan elemen khusus 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 sudah ditentukan, segera selesaikan. Menolak jika nama tag tidak nama elemen khusus yang valid.
Contoh
customElements.whenDefined('app-drawer').then(() => {
console.log('ready!');
});
Dukungan histori dan browser
Jika Anda telah mengikuti komponen web selama beberapa tahun terakhir, Anda akan
Chrome 36+ menerapkan versi {i>Custom Elements API<i} yang menggunakan
document.registerElement()
, bukan customElements.define()
. Itu sekarang
dianggap sebagai versi standar yang tidak digunakan lagi, yang disebut v0.
customElements.define()
adalah fitur terbaru dan vendor browser apa
mulai diterapkan. Elemen ini disebut Custom Elements v1.
Jika Anda tertarik dengan spesifikasi v0 yang lama, lihat html5rock artikel ini.
Dukungan browser
Chrome 54 (status), Safari 10.1 (status), dan Firefox 63 (status) memiliki Elemen Kustom v1. Edge telah dimulai pengembangan.
Untuk mendeteksi elemen khusus fitur, periksa keberadaan elemen
window.customElements
:
const supportsCustomElementsV1 = 'customElements' in window;
Polyfill
Sampai dukungan browser tersedia secara luas, ada polyfill mandiri yang tersedia untuk Custom Elements v1. Namun, sebaiknya gunakan webcomponents.js loader untuk memuat polyfill komponen web secara optimal. Loader menggunakan deteksi fitur untuk hanya memuat pollingyfill yang diperlukan secara asinkron yang diperlukan oleh browser.
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 platform baru lainnya
seperti Shadow DOM dan <template>
, lalu kita mulai menyadari
gambar Komponen Web:
- Lintas browser (standar web) untuk membuat dan memperluas komponen yang dapat digunakan kembali.
- Tidak memerlukan library atau framework untuk memulai. FTW JS/HTML biasa!
- Menyediakan model pemrograman yang familier. Ini hanya DOM/CSS/HTML.
- Berfungsi dengan baik dengan fitur platform web baru lainnya (Shadow DOM,
<template>
, CSS properti khusus, dll.) - Terintegrasi erat dengan DevTools browser.
- Memanfaatkan fitur aksesibilitas yang ada.