Halo Komponen Web
Jika Anda pernah mendengar tentang Komponen Web tetapi belum pernah membuatnya sendiri, Anda telah datang ke tempat yang tepat. Saatnya telah tiba! Mari membangun Komponen Web bersama-sama!
Ketika saya memiliki kesempatan untuk mengajari orang-orang tentang Komponen Web, saya biasanya ingin memulai dengan sesuatu yang sederhana yang banyak dari kita ketahui dari “dunia nyata”. Jadi, mari kita buat "tag nama" Komponen Web yang terlihat seperti ini…
INFO: Apa itu Komponen Web? Istilah "Komponen Web" adalah istilah umum yang mencakup kumpulan beberapa standar W3C dalam HTML dan CSS, yang bersama-sama memungkinkan pembuatan dan berbagi elemen (komponen) asli platform web yang dapat digunakan kembali.
Langkah Nol
- Mulailah dengan dokumen HTML dasar yang memiliki skrip modul JS yang menunjuk ke file JavaScript (sementara) kosong.
- Di badan dokumen, tambahkan
name-tagelemen dengan teks "Komponen Web" sebagai kontennya. Ini adalah Komponen Web yang pada akhirnya ingin kami kerjakan. - Mulai server web dan ramban ke file HTML Anda. Anda akan melihat teks "Komponen Web" ditampilkan di browser Anda.
<!DOCTYPE html>
<html>
<head>
<title>Hello Web Components</title>
</head>
<body>
<name-tag greeting="Hola">Web Components</name-tag>
<script type="module" src="index.js"></script>
</body>
</html>
// Nothing here yet. We'll add our Web Component code in the next step.
Langkah pertama
- Dalam file JavaScript Anda, nyatakan perilaku untuk
name-tagelemen khusus Anda dengan membuat kelas bernamaNameTagyang diperluas dariHTMLElement. Semua Komponen Web mewarisi dariHTMLElementelemen bawaan sepertidiv,span, daninput. - Daftarkan elemen Anda ke browser dengan memanggil
customElements.define(...), memberikan nama tag HTML yang diinginkan danNameTagkelas sebagai argumen. - Refresh browser dan Anda akan tetap melihat teks yang sama seperti sebelumnya. Namun, jika Anda memeriksa elemennya
name-tag, Anda akan melihat bahwa itu bukan hanya sebuahHTMLElementtetapi konstruktornya sekarangNameTagjuga.
class NameTag extends HTMLElement {
}
customElements.define('name-tag', NameTag);
Langkah Kedua
- Tambahkan konstruktor ke kelas Anda. Setelah panggilan ke
super(), panggilthis.attachShadow(...)untuk membuat Shadow DOM untuk elemen khusus Anda. Shadow DOM seperti memiliki dokumen HTML pribadi yang hanya dapat dirender oleh komponen Anda. Lewati opsi{ mode: ‘open’ }sehingga shadow root dan elemen internalnya masih dapat diakses secara eksternal melalui JavaScript dan melalui alat pengembang. - Setelah Shadow DOM terpasang, Anda dapat mengakses
this.shadowRootdan mengatur propertinyainnerHTMLke HTML yang Anda pilih. - Refresh browser dan amati bahwa
innerHTMLkonten Shadow DOM Anda sekarang sedang dirender tetapi konten elemen itu sendiri, teks "Komponen Web", tidak lagi dirender. Kemana perginya? - Buka inspektur dan verifikasi bahwa ada
#shadow-rootnode yang dapat Anda periksa untuk melihat apa yang Anda berikan sebagaiinnerHTML. Perhatikan bahwa konten Anda juga masih dalam DOM, meskipun tidak dirender. Alasan tidak dirender adalah karena browser tidak mengetahui cara menyusun konten Light DOM dengan Shadow DOM. Kami akan memperbaikinya selanjutnya.
class NameTag extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = 'Rendering from Shadow DOM';
}
}
customElements.define('name-tag', NameTag);
Langkah ketiga
- Revisi HTML yang ditempatkan di shadow root sehingga menyertakan elemen
<slot>. Ini memberi tahu browser cara menyusun Light DOM dan Shadow DOM Anda secara bersamaan. Slot tersebut menyediakan lokasi untuk "memproyeksikan" atau merender konten Light DOM ke dalam Shadow DOM. Konten masih ada di Light DOM, tetapi dirender seolah-olah berada di lokasi slot. - Refresh browser Anda dan amati bahwa sekarang konten Light dan Shadow DOM Anda telah disusun bersama dengan benar.
class NameTag extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = 'HELLO <slot></slot>';
}
}
customElements.define('name-tag', NameTag);
Langkah Empat
- Agar
greetingatribut kami berfungsi, kami harus memberi tahu platform bahwa adagreetingatribut yang ingin kami amati. Buat pengambil statis bernamaobservedAttributesyang mengembalikan larik nama atribut untuk diamati oleh platform. Array harus berisi nama atribut tunggal:['greeting']. - Selanjutnya, implementasikan an
attributeChangedCallback()yang dapat dipanggil oleh platform setiap kali atribut yang diamati berubah. - Tambahkan pengambil/penyetel properti untuk menyediakan akses properti ke atribut, karena sebagian besar elemen HTML memiliki properti dan atribut. Ini akan memastikan elemen khusus kami terasa seperti hal lain di platform dan berfungsi dengan benar dengan kerangka kerja front-end populer yang menetapkan atribut dan properti. Pengambil dan penyetel hanya dapat mendelegasikan ke
getAttribute()dansetAttribute()API dariHTMLElement. - Ekstrak
renderfungsi yang mengambil komponen sebagai input dan panggil dariattributeChangedCallback()sehingga dapat memperbarui renderingnya saat status elemen berubah. Hapus kode yang diaturinnerHTMLdi konstruktor. Ini tidak lagi diperlukan. - Kami juga dapat memperkenalkan a
connectedCallback().Platform akan memanggil ini saat elemen terhubung ke dokumen. Kami akan menggunakan ini untuk memastikan bahwa ada nilai default untukgreetingjika tidak ditetapkan pada saat elemen terhubung. - Segarkan browser untuk melihat bahwa
greetingatribut sekarang mulai berlaku. Eksperimen dengan menggunakan alat debug untuk menyetelgreetingproperti dan atribut. Coba tempatkan breakpoint di fileattributeChangedCallback().
const render = x => `${x.greeting.toUpperCase()} <slot></slot>`;
class NameTag extends HTMLElement {
static get observedAttributes() {
return ['greeting'];
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
get greeting() {
return this.getAttribute('greeting');
}
set greeting(value) {
this.setAttribute('greeting', value);
}
connectedCallback() {
if (!this.greeting) {
this.greeting = 'Hello';
}
}
attributeChangedCallback(name, oldValue, newValue) {
this.shadowRoot.innerHTML = render(this);
}
}
customElements.define('name-tag', NameTag);
- Mari tingkatkan
renderfungsi kita sehingga memberikan struktur yang lebih realistis. - Segarkan browser untuk memastikan bahwa struktur baru dirender dengan benar.
const render = x => `
<div part="header" class="header">
<h3 part="greeting">${x.greeting.toUpperCase()}</h3>
<h4 part="message">my name is</h4>
</div>
<div part="body" class="body">
<slot></slot>
</div>
<div part="footer" class="footer"></div>
`;
Langkah Enam
- Memanfaatkan standar baru StyleSheets yang Dapat Dibangun dan StyleSheet yang Diadopsi, buat instance
CSSStyleSheetdan panggilreplaceSync()untuk menyetel teks CSS-nya. - Di konstruktor elemen Anda, tambahkan gaya khusus Anda ke
adoptedStyleSheetselemenshadowRoot. - Segarkan browser Anda untuk melihat komponen yang ditata sepenuhnya.
const styles = new CSSStyleSheet();
styles.replaceSync(`
:host {
--default-color: red;
--default-radius: 6px;
--default-depth: 5px;
display: inline-block;
contain: content;
color: white;
background: var(--color, var(--default-color));
border-radius: var(--radius, var(--default-radius));
min-width: 325px;
text-align: center;
box-shadow: 0 0 var(--depth, var(--default-depth)) rgba(0,0,0,.5);
}
.header {
margin: 16px 0;
position: relative;
}
h3 {
font-weight: bold;
font-family: sans-serif;
letter-spacing: 4px;
font-size: 32px;
margin: 0;
padding: 0;
}
h4 {
font-family: sans-serif;
font-size: 18px;
margin: 0;
padding: 0;
}
.body {
background: white;
color: black;
padding: 32px 8px;
font-size: 42px;
font-family: cursive;
}
.footer {
height: 16px;
background: var(--color, var(--default-color));
border-radius: 0 0 var(--radius, var(--default-radius)) var(--radius, var(--default-radius));
}
`);
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.adoptedStyleSheets = [
...this.shadowRoot.adoptedStyleSheets,
styles
];
}
Baca terus untuk mengetahui lebih dalam dan temukan beberapa sumber belajar dan perpustakaan tambahan.
Lebih Dalam
Properti Kustom CSS (alias Variabel CSS)
Cara umum untuk mengaktifkan gaya elemen khusus adalah mendasarkan gaya komponen pada Properti Kustom CSS (alias Variabel CSS). Properti Kustom dideklarasikan dengan awalan tanda hubung ganda dan direferensikan dengan var(...)fungsi. Saat mereferensikan variabel, Anda juga bisa memberikan nilai fallback, yang juga bisa menjadi variabel lain. Anda dapat melihat teknik ini digunakan di seluruh CSS di atas. Untuk bermain dengan ini, buat beberapa <name-tag>elemen di halaman Anda dan kemudian gunakan inspektur gaya browser untuk menyetel ——color, ——depth, dan——radiusproperti pada elemen individu atau pada elemen induk. Meskipun Shadow DOM mengenkapsulasi gaya, CSS Custom Properties “menembus” batas Shadow DOM secara default. Ini memungkinkan untuk membuat sistem bertema yang bekerja di seluruh pustaka komponen atau aplikasi. Dan ingat, Properti Kustom CSS dapat digunakan bersama dengan CSS calc(...)untuk efek yang menakjubkan.
- Baca selengkapnya tentang Properti Kustom CSS di MDN.
- Baca lebih lanjut tentang CSS Calc di MDN.
Gaya Shadow DOM juga dapat memanfaatkan pemilih khusus, seperti :host pemilih yang menargetkan elemen itu sendiri. Merupakan praktik terbaik untuk menyiapkan gaya host untuk default displaydan disabledstatus. Lihat containproperti CSS untuk cara meningkatkan kinerja render komponen juga. Jika Anda memiliki gaya khusus untuk elemen yang ditempatkan di dalam konten elemen Anda, Anda dapat menentukannya dengan menggunakan pemilih ::slotted().
- Baca lebih lanjut tentang :host di MDN.
- Baca lebih lanjut tentang ::slotted di MDN.
- Baca lebih lanjut tentang Isi CSS di MDN.
Karena adoptedStyleSheetsbelum diimplementasikan di semua browser (Saya sedang melihat Anda Safari!), Untuk komponen produksi apa pun yang Anda buat, Anda akan ingin mendeteksi fitur dan mundur ke injeksi elemen gaya sesuai kebutuhan. Ini adalah sesuatu yang ditangani oleh banyak pustaka Komponen Web (misalnya, FAST ) untuk Anda secara otomatis.
- Baca lebih lanjut tentang lembar gaya yang diadopsi di MDN.
Anda mungkin telah memperhatikan bahwa beberapa elemen di shadow DOM di atas memiliki sebuah partatribut. Hal ini memungkinkan pengembang komponen web untuk mendeklarasikan bagian dari komponen yang dapat ditata secara eksternal oleh konsumen komponen. Untuk mencobanya, buat beberapa <name-tag>elemen di halaman Anda, masing-masing dengan elemen class. Kemudian buat CSS yang menargetkan bagian berdasarkan pemilih kelas dan menyesuaikan gaya sapaan. Berikut tampilannya:
.large-greeting::part(greeting) {
font-size: 64px;
}
Siklus Hidup Komponen Web
Dalam NameTagelemen kami, kami menggunakan connectedCallback(...), yang merupakan salah satu pengait siklus hidup Komponen Web standar. Tapi itu bukan satu-satunya. Berikut daftar callback siklus hidup yang tersedia yang dapat Anda gunakan di komponen Anda:
constructor()— Berjalan saat elemen dibuat atau ditingkatkan.connectedCallback()— Berjalan saat elemen dimasukkan ke dalam DOM.disconnectedCallback()— Berjalan saat elemen dihapus dari DOM.attributedChangedCallback(attrName, oldValue, newValue)— Berjalan kapan pun salah satu atribut khusus elemen berubah.adoptedCallback()— Berjalan saat elemen dipindahkan dari arusnyadocumentke yang barudocumentmelalui panggilan keadoptNode(…)API.
Seperti disebutkan sebelumnya, jumlah boilerplate yang terlibat saat membuat Komponen Web sederhana tampaknya sedikit banyak. Hal ini karena standar Komponen Web hanya menyediakan kemampuan tingkat rendah, dengan sedikit atau tanpa opini. Namun, bagaimana jika serangkaian opini opsional diperkenalkan? Bisakah itu mengurangi jumlah kode dan memberikan manfaat lain? Banyak orang yang membangun Komponen Web berpikir demikian, dan dengan demikian menggunakan semacam pustaka pembantu kecil. Sebagai penutup posting ini, saya ingin menunjukkan kepada Anda komponen yang sama, dibangun dengan FAST , yang merampingkan proses pembuatan Komponen Web dan menyediakan alat tambahan untuk membangun solusi yang lebih kompleks. Inilah NameTagKomponen Web yang diimplementasikan dengan FAST , menggunakan TypeScript:
import {
attr,
css,
customElement,
FASTElement,
html
} from "@microsoft/fast-element";
// Create a reactive template based on the element's state.
const template = html<NameTag>`
<div part="header" class="header">
<h3 part="greeting">${x => x.greeting.toUpperCase()}</h3>
<h4 part="message">my name is</h4>
</div>
<div part="body" class="body">
<slot></slot>
</div>
<div part="footer" class="footer"></div>
`;
// Create styles that automatically use adopted style sheets when present.
const styles = css`
:host {
--default-color: red;
--default-radius: 6px;
--default-depth: 5px;
display: inline-block;
contain: content;
color: white;
background: var(--color, var(--default-color));
border-radius: var(--radius, var(--default-radius));
min-width: 325px;
text-align: center;
box-shadow: 0 0 var(--depth, var(--default-depth)) rgba(0,0,0,.5);
}
.header {
margin: 16px 0;
position: relative;
}
h3 {
font-weight: bold;
font-family: sans-serif;
letter-spacing: 4px;
font-size: 32px;
margin: 0;
padding: 0;
}
h4 {
font-family: sans-serif;
font-size: 18px;
margin: 0;
padding: 0;
}
.body {
background: white;
color: black;
padding: 32px 8px;
font-size: 42px;
font-family: cursive;
}
.footer {
height: 16px;
background: var(--color, var(--default-color));
border-radius: 0 0 var(--radius, var(--default-radius)) var(--radius, var(--default-radius));
}
`;
// Define the element with a name, template, and styles.
@customElement({
name: 'name-tag',
template,
styles
})
class NameTag extends FASTElement { // Remove boilerplate w/ base class.
@attr greeting = 'Hello'; // A reactive HTML attribute with a default.
}
Perhatikan bagaimana semua boilerplate hilang? Berikut adalah beberapa hal yang FAST lakukan untuk Anda:
- Templat — FAST menyediakan mesin templat berbasis reaktivitas berperforma tinggi, termasuk dukungan untuk MVVM tingkat lanjut dalam skala besar.
- Gaya — FAST secara otomatis mendeteksi keberadaan lembar gaya yang diadopsi dan menggunakannya jika memungkinkan. Ini juga menyimpan dan menggunakan kembali instance style sheet di seluruh instance Komponen Web untuk meningkatkan kinerja dan manajemen memori.
- FASTElement — Kelas dasar secara otomatis menyiapkan Shadow DOM dan terhubung ke siklus hidup untuk menangani rendering dengan template yang disediakan. Dekorator menyediakan cara deklaratif untuk menghubungkan template, gaya, dan kelas Anda, sambil mendaftarkannya ke platform menggunakan nama yang disediakan.
- Atribut — Alih-alih mendeklarasikan getter/setter secara manual, menyiapkan
observedAttributesarray, dan menangani nilai default dan callback perubahan atribut, Anda cukup mendekorasi bidang dengan@attrdanFASTElementmenangani semuanya untuk Anda.
Tertarik untuk mempelajari lebih lanjut atau bergabung dengan komunitas FAST dan Komponen Web yang terus berkembang?
- Temukan CEPAT di GitHub.
- Jelajahi Dokumentasi CEPAT lengkap.
- Berlangganan ke Blog CEPAT.
- Bergabunglah dengan server Perselisihan CEPAT.

![Apa itu Linked List? [Bagian 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































