[Nasihat membaca] 19 bagian siklus lainnya Kami sajikan kepada Anda terjemahan dari 19 artikel dari seri
SessionStack tentang fitur berbagai mekanisme ekosistem JavaScript. Hari ini kita akan berbicara tentang standar Elemen Kustom - yang disebut "elemen kustom". Kami akan berbicara tentang tugas apa yang mereka biarkan selesaikan, dan bagaimana membuat dan menggunakannya.
Ulasan
Dalam salah satu artikel sebelumnya dalam seri ini, kami berbicara tentang
Shadow DOM dan beberapa teknologi lain yang merupakan bagian dari fenomena yang lebih besar - komponen web. Komponen web dirancang untuk memungkinkan pengembang memperluas fitur standar HTML dengan membuat elemen yang ringkas, modular, dan dapat digunakan kembali. Ini adalah standar W3C yang relatif baru yang telah diperhatikan oleh produsen dari semua browser terkemuka. Dia dapat ditemukan dalam produksi, meskipun, tentu saja, sementara karyanya disediakan oleh polifil (kita akan membicarakannya nanti).
Seperti yang mungkin sudah Anda ketahui, browser memberi kami beberapa alat penting untuk mengembangkan situs web dan aplikasi web. Ini tentang HTML, CSS, dan JavaScript. HTML digunakan untuk membuat struktur halaman web, berkat CSS, tampilannya bagus, dan JavaScript bertanggung jawab untuk fitur-fitur interaktif. Namun, sebelum kemunculan komponen web, tidak mudah untuk mengaitkan tindakan yang diimplementasikan JavaScript dengan struktur HTML.
Faktanya, di sini kami akan mempertimbangkan dasar komponen web - Elemen Kustom. Singkatnya, API yang dirancang untuk bekerja dengannya memungkinkan pemrogram untuk membuat elemen HTML mereka sendiri dengan logika dan gaya JavaScript bawaan yang dijelaskan oleh CSS. Banyak elemen kustom yang membingungkan dengan teknologi Shadow DOM. Namun, ini adalah dua hal yang sangat berbeda yang, pada kenyataannya, saling melengkapi, tetapi tidak dapat dipertukarkan.
Beberapa kerangka kerja (seperti Angular atau Bereaksi) mencoba memecahkan masalah yang sama yang elemen kustom pecahkan dengan memperkenalkan konsep mereka sendiri. Elemen khusus dapat dibandingkan dengan arahan sudut atau dengan komponen Bereaksi. Namun, elemen khusus adalah fitur standar browser, Anda tidak perlu menggunakan apa pun selain JavaScript, HTML, dan CSS biasa untuk menggunakannya. Tentu saja, ini tidak memungkinkan kita untuk mengatakan bahwa mereka adalah pengganti kerangka kerja JS biasa. Kerangka kerja modern memberi kita lebih dari sekadar kemampuan untuk mensimulasikan perilaku elemen kustom. Sebagai hasilnya, kita dapat mengatakan bahwa kerangka kerja dan elemen pengguna adalah teknologi yang dapat digunakan bersama untuk menyelesaikan tugas pengembangan web.
API
Sebelum kita melanjutkan, mari kita lihat peluang apa yang diberikan API untuk bekerja dengan elemen khusus. Yaitu, kita berbicara tentang objek
customElements
global yang memiliki beberapa metode:
- Metode
define(tagName, constructor, options)
memungkinkan Anda untuk mendefinisikan (membuat, mendaftar) elemen pengguna baru. Dibutuhkan tiga argumen - nama tag untuk elemen pengguna, sesuai dengan aturan penamaan untuk elemen tersebut, deklarasi kelas, dan objek dengan parameter. Saat ini, hanya satu parameter yang didukung - extends
, yang merupakan string yang menentukan nama elemen inline yang akan diperluas. Fitur ini digunakan untuk membuat versi khusus dari elemen standar. - Metode
get(tagName)
mengembalikan konstruktor dari elemen pengguna, asalkan elemen ini sudah didefinisikan, jika tidak maka pengembaliannya undefined
. Dibutuhkan satu argumen - tag nama elemen pengguna. - Metode
whenDefined(tagName)
mengembalikan janji yang diselesaikan setelah elemen pengguna dibuat. Jika suatu elemen sudah ditentukan, janji ini segera diselesaikan. Janji ditolak jika nama tag yang diteruskan bukan nama tag yang valid untuk elemen pengguna. Metode ini menerima nama tag elemen pengguna.
Buat item khusus
Membuat elemen khusus sangat sederhana. Untuk melakukan ini, dua hal harus dilakukan: membuat deklarasi kelas untuk elemen yang harus memperluas kelas
HTMLElement
dan mendaftarkan elemen ini di bawah nama yang dipilih. Begini tampilannya:
class MyCustomElement extends HTMLElement { constructor() { super();
Jika Anda tidak ingin mencemari ruang lingkup saat ini, Anda dapat menggunakan kelas anonim:
customElements.define('my-custom-element', class extends HTMLElement { constructor() { super();
Seperti yang Anda lihat dari contoh, elemen pengguna terdaftar menggunakan metode
customElements.define(...)
sudah Anda kenal.
Masalah yang diselesaikan elemen khusus
Mari kita bicara tentang masalah yang memungkinkan kita untuk menyelesaikan elemen khusus. Salah satunya adalah memperbaiki struktur kode dan menghilangkan apa yang disebut "sup tag div" (sup sup). Fenomena ini adalah struktur kode yang sangat umum dalam aplikasi web modern, di mana ada banyak elemen
div
melekat. Begini tampilannya:
<div class="top-container"> <div class="middle-container"> <div class="inside-container"> <div class="inside-inside-container"> <div class="are-we-really-doing-this"> <div class="mariana-trench"> β¦ </div> </div> </div> </div> </div> </div>
Kode HTML semacam itu digunakan untuk alasan yang dapat dibenarkan - kode ini menggambarkan tata letak halaman dan memastikan tampilan yang benar di layar. Namun, ini merusak pembacaan kode HTML dan mempersulit pemeliharaannya.
Misalkan kita memiliki komponen yang terlihat seperti gambar berikut.
Penampilan komponenMenggunakan pendekatan tradisional untuk menggambarkan hal-hal seperti itu, kode berikut akan sesuai dengan komponen ini:
<div class="primary-toolbar toolbar"> <div class="toolbar"> <div class="toolbar-button"> <div class="toolbar-button-outer-box"> <div class="toolbar-button-inner-box"> <div class="icon"> <div class="icon-undo"> </div> </div> </div> </div> </div> <div class="toolbar-button"> <div class="toolbar-button-outer-box"> <div class="toolbar-button-inner-box"> <div class="icon"> <div class="icon-redo"> </div> </div> </div> </div> </div> <div class="toolbar-button"> <div class="toolbar-button-outer-box"> <div class="toolbar-button-inner-box"> <div class="icon"> <div class="icon-print"> </div> </div> </div> </div> </div> <div class="toolbar-toggle-button toolbar-button"> <div class="toolbar-button-outer-box"> <div class="toolbar-button-inner-box"> <div class="icon"> <div class="icon-paint-format"> </div> </div> </div> </div> </div> </div> </div>
Sekarang bayangkan kita bisa, alih-alih kode ini, menggunakan deskripsi komponen ini:
<primary-toolbar> <toolbar-group> <toolbar-button class="icon-undo"></toolbar-button> <toolbar-button class="icon-redo"></toolbar-button> <toolbar-button class="icon-print"></toolbar-button> <toolbar-toggle-button class="icon-paint-format"></toolbar-toggle-button> </toolbar-group> </primary-toolbar>
Saya yakin semua orang akan setuju bahwa fragmen kode kedua terlihat jauh lebih baik. Kode semacam itu lebih mudah dibaca, lebih mudah dipelihara, dan dapat dipahami oleh pengembang dan peramban. Itu semua bermuara pada fakta bahwa itu lebih sederhana daripada yang ada di mana banyak tag
div
bersarang.
Masalah selanjutnya yang dapat diselesaikan dengan elemen kustom adalah penggunaan kembali kode. Kode yang ditulis pengembang tidak hanya berfungsi, tetapi juga didukung. Menggunakan kembali kode, sebagai lawan untuk terus-menerus menulis konstruksi yang sama, meningkatkan kemampuan dukungan proyek.
Berikut adalah contoh sederhana yang akan membantu Anda lebih memahami ide ini. Misalkan kita memiliki elemen berikut:
<div class="my-custom-element"> <input type="text" class="email" /> <button class="submit"></button> </div>
Jika Anda terus-menerus membutuhkannya, maka, dengan pendekatan yang biasa, kami harus menulis kode HTML yang sama berulang kali. Sekarang bayangkan Anda perlu membuat perubahan pada kode ini yang harus tercermin di mana pun ia digunakan. Ini berarti bahwa kita perlu menemukan semua tempat di mana fragmen ini digunakan, dan kemudian membuat perubahan yang sama di mana-mana. Itu panjang, keras dan penuh dengan kesalahan.
Akan jauh lebih baik jika kita bisa di mana elemen ini diperlukan, cukup tulis yang berikut ini:
<my-custom-element></my-custom-element>
Namun, aplikasi web modern lebih dari sekadar HTML statis. Mereka interaktif. Sumber interaktivitas mereka adalah JavaScript. Biasanya, untuk memberikan kemampuan seperti itu, beberapa elemen dibuat, kemudian pendengar acara terhubung dengannya, yang memungkinkan mereka untuk menanggapi pengaruh pengguna. Misalnya, mereka dapat merespons klik, βmelayangβ dari penunjuk tetikus di atasnya, menyeretnya ke layar, dan sebagainya. Berikut cara menghubungkan pendengar acara ke elemen yang terjadi saat Anda mengkliknya dengan mouse:
var myDiv = document.querySelector('.my-custom-element'); myDiv.addEventListener('click', _ => { myDiv.innerHTML = '<b> I have been clicked </b>'; });
Dan di sini adalah kode HTML untuk elemen ini:
<div class="my-custom-element"> I have not been clicked yet. </div>
Dengan menggunakan API untuk bekerja dengan elemen kustom, semua logika ini dapat dimasukkan dalam elemen itu sendiri. Sebagai perbandingan - di bawah ini adalah kode untuk mendeklarasikan elemen kustom yang mencakup pengendali event:
class MyCustomElement extends HTMLElement { constructor() { super(); var self = this; self.addEventListener('click', _ => { self.innerHTML = '<b> I have been clicked </b>'; }); } } customElements.define('my-custom-element', MyCustomElement);
Dan di sini adalah tampilannya di kode HTML halaman:
<my-custom-element> I have not been clicked yet </my-custom-element>
Pada pandangan pertama, sepertinya lebih banyak baris kode JS diperlukan untuk membuat elemen kustom. Namun, dalam aplikasi dunia nyata, jarang terjadi bahwa elemen tersebut dibuat hanya untuk digunakan hanya sekali. Fenomena khas lain dalam aplikasi web modern adalah sebagian besar elemen di dalamnya dibuat secara dinamis. Ini mengarah pada kebutuhan untuk mendukung dua skenario yang berbeda dalam bekerja dengan elemen - situasi ketika mereka ditambahkan ke halaman secara dinamis menggunakan JavaScript, dan situasi ketika mereka dijelaskan dalam struktur HTML asli halaman. Berkat penggunaan elemen khusus, pekerjaan dalam dua situasi ini disederhanakan.
Akibatnya, jika kami merangkum hasil bagian ini, kami dapat mengatakan bahwa elemen pengguna membuat kode lebih jelas, menyederhanakan dukungannya, membantu memecahnya menjadi modul-modul kecil, yang mencakup semua fungsi yang diperlukan dan cocok untuk digunakan kembali.
Sekarang kita telah membahas masalah umum bekerja dengan elemen khusus, mari kita bicara tentang fitur-fiturnya.
Persyaratan
Sebelum Anda mulai mengembangkan elemen kustom Anda sendiri, Anda harus tahu tentang beberapa aturan yang harus Anda ikuti saat membuatnya. Inilah mereka:
- Nama komponen harus menyertakan tanda hubung (
-
simbol). Berkat ini, parser HTML dapat membedakan antara elemen yang disematkan dan pengguna. Selain itu, pendekatan ini memastikan bahwa tidak ada tabrakan nama dengan elemen bawaan (baik dengan yang ada sekarang maupun yang muncul di masa depan). Misalnya, nama sebenarnya dari elemen kustom adalah >my-custom-element<
elemen >my-custom-element<
, dan nama-nama >myCustomElement<
dan <my_custom_element>
tidak cocok. - Dilarang mendaftarkan tag yang sama lebih dari satu kali. Mencoba melakukan ini akan menyebabkan browser
DOMException
kesalahan DOMException
. Elemen khusus tidak dapat didefinisikan ulang. - Tag khusus tidak dapat ditutup sendiri. Pengurai HTML hanya mendukung serangkaian tag penutup otomatis standar terbatas (misalnya,
<img>
, <link>
, <br>
).
Kemungkinan
Mari kita bicara tentang apa yang dapat Anda lakukan dengan elemen khusus. Jika Anda menjawab pertanyaan ini secara singkat, ternyata Anda dapat melakukan banyak hal menarik dengannya.
Salah satu fitur yang paling menonjol dari elemen kustom adalah bahwa deklarasi kelas elemen merujuk ke elemen DOM itu sendiri. Ini berarti Anda dapat menggunakan kata kunci ini dalam iklan untuk menghubungkan pendengar acara, untuk mengakses properti, ke simpul anak, dan sebagainya.
class MyCustomElement extends HTMLElement {
Ini, tentu saja, memungkinkan untuk menulis data baru ke simpul anak elemen. Namun, melakukan ini tidak disarankan, karena ini dapat menyebabkan perilaku elemen yang tidak terduga. Jika Anda membayangkan bahwa Anda menggunakan elemen yang dirancang oleh orang lain, maka Anda mungkin akan terkejut jika markup Anda sendiri yang ditempatkan di elemen diganti dengan sesuatu yang lain.
Ada beberapa metode yang memungkinkan Anda untuk mengeksekusi kode pada titik-titik tertentu dalam siklus hidup suatu elemen.
- Metode
constructor
dipanggil sekali, ketika membuat atau "meningkatkan" elemen (kita akan membicarakan ini di bawah). Paling sering digunakan untuk menginisialisasi keadaan elemen, untuk menghubungkan pendengar acara, membuat Shadow DOM, dan sebagainya. Jangan lupa bahwa Anda selalu perlu memanggil super()
di konstruktor. - Metode
connectedCallback
dipanggil setiap kali elemen ditambahkan ke DOM. Itu dapat digunakan (dan ini adalah persis cara yang disarankan untuk menggunakannya) untuk menunda pelaksanaan tindakan apa pun hingga saat elemen muncul di halaman (misalnya, dengan cara ini Anda dapat menunda pemuatan beberapa data). - Metode
disconnectedCallback
dipanggil ketika item dihapus dari DOM. Biasanya digunakan untuk membebaskan sumber daya. Perhatikan bahwa metode ini tidak dipanggil jika pengguna menutup tab browser dengan halaman. Karena itu, jangan bergantung padanya ketika diperlukan untuk melakukan beberapa tindakan yang sangat penting. - Metode
attributeChangedCallback
dipanggil ketika attributeChangedCallback
elemen ditambahkan, dihapus, diperbarui, atau diganti. Selain itu, ini disebut ketika elemen dibuat oleh pengurai. Namun, perhatikan bahwa metode ini hanya berlaku untuk atribut yang terdaftar di properti yang observedAttributes
. - Metode
adoptedCallback
dipanggil ketika metode document.adoptNode(...)
digunakan, yang digunakan untuk memindahkan node ke dokumen lain.
Harap dicatat bahwa semua metode di atas sinkron. Misalnya, metode
connectedCallback
panggilan dipanggil segera setelah elemen ditambahkan ke DOM, dan sisa program menunggu penyelesaian metode ini.
Refleksi Properti
Elemen HTML tertanam memiliki satu fitur yang sangat nyaman: refleksi properti. Berkat mekanisme ini, nilai beberapa properti secara langsung tercermin dalam DOM sebagai atribut. Katakanlah ini adalah karakteristik dari properti
id
. Sebagai contoh, kami melakukan operasi berikut:
myDiv.id = 'new-id';
Perubahan yang relevan akan memengaruhi DOM:
<div id="new-id"> ... </div>
Mekanisme ini beroperasi dalam arah yang berlawanan. Ini sangat berguna karena memungkinkan Anda untuk mengkonfigurasi elemen deklaratif.
Elemen khusus tidak memiliki fitur bawaan ini, tetapi Anda dapat menerapkannya sendiri. Agar beberapa properti elemen pengguna memiliki perilaku yang sama, Anda dapat mengonfigurasi getter dan setter mereka.
class MyCustomElement extends HTMLElement {
Memperluas item yang ada
API elemen khusus memungkinkan Anda tidak hanya membuat elemen HTML baru, tetapi juga memperluas elemen yang sudah ada. Selain itu, kita berbicara tentang elemen standar dan elemen kustom. Ini dilakukan dengan menggunakan
extends
ketika mendeklarasikan sebuah kelas:
class MyAwesomeButton extends MyButton {
Elemen standar yang diperluas juga disebut "elemen bawaan yang dapat disesuaikan".
Disarankan untuk membuat aturan untuk selalu memperluas elemen yang ada, dan melakukannya secara progresif. Ini akan memungkinkan Anda untuk menyimpan dalam elemen baru kemampuan yang diimplementasikan dalam elemen yang dibuat sebelumnya (yaitu, properti, atribut, fungsi).
Harap perhatikan bahwa sekarang elemen bawaan khusus hanya didukung di Chrome 67+. Ini akan muncul di browser lain, namun, diketahui bahwa pengembang Safari memutuskan untuk tidak menerapkan kesempatan ini.
Perbarui Item
Seperti yang telah disebutkan, metode
customElements.define(...)
digunakan untuk mendaftarkan elemen kustom. Namun, pendaftaran tidak dapat disebut tindakan yang harus dilakukan sejak awal. Registrasi elemen pengguna dapat ditunda untuk sementara waktu, apalagi, kali ini mungkin datang bahkan ketika elemen sudah ditambahkan ke DOM. Proses ini disebut pemutakhiran. Untuk mengetahui kapan suatu barang akan didaftarkan, peramban menyediakan metode
customElements.whenDefined(...)
. Dia diberi nama tag elemen, dan dia mengembalikan janji yang diselesaikan setelah pendaftaran elemen.
customElements.whenDefined('my-custom-element').then(_ => { console.log('My custom element is defined'); });
Misalnya, Anda mungkin perlu menunda pendaftaran suatu elemen hingga anak-anaknya diumumkan. Perilaku seperti itu bisa sangat berguna jika proyek memiliki elemen pengguna bersarang. Terkadang orangtua dapat mengandalkan implementasi elemen anak. Dalam hal ini, Anda perlu memastikan bahwa anak-anak terdaftar sebelum orang tua.
Dom bayangan
Seperti yang telah disebutkan, elemen khusus dan Shadow DOM adalah teknologi pelengkap. Yang pertama memungkinkan Anda untuk merangkum logika JS di elemen pengguna, dan yang kedua memungkinkan Anda untuk membuat lingkungan terisolasi untuk fragmen DOM yang tidak terpengaruh oleh apa yang ada di luar mereka. Jika Anda merasa perlu lebih memahami konsep Shadow DOM, lihat salah satu
publikasi kami
sebelumnya .
Berikut cara menggunakan Shadow DOM untuk elemen khusus:
class MyCustomElement extends HTMLElement {
Seperti yang Anda lihat, memanggil
this.attachShadow
memainkan peran penting di
this.attachShadow
.
Pola
Dalam salah satu artikel kami
sebelumnya , kami berbicara sedikit tentang templat, meskipun sebenarnya layak untuk artikel terpisah. Di sini kita akan melihat contoh sederhana tentang cara menyematkan templat di elemen khusus saat dibuat. Jadi, menggunakan
<template>
, Anda dapat menjelaskan fragmen DOM yang akan diproses oleh parser, tetapi tidak akan ditampilkan pada halaman:
<template id="my-custom-element-template"> <div class="my-custom-element"> <input type="text" class="email" /> <button class="submit"></button> </div> </template>
Berikut cara menerapkan templat di elemen khusus:
let myCustomElementTemplate = document.querySelector('#my-custom-element-template'); class MyCustomElement extends HTMLElement {
Seperti yang Anda lihat, ada kombinasi elemen khusus, DOM Bayangan, dan template. Ini memungkinkan kami untuk membuat elemen yang terisolasi di ruangnya sendiri, di mana struktur HTML dipisahkan dari logika JS.
Stilisasi
Sejauh ini, kami hanya berbicara tentang JavaScript dan HTML, mengabaikan CSS. Karena itu, kita sekarang menyentuh topik gaya. Jelas, kita perlu cara untuk menata elemen khusus. Gaya dapat ditambahkan di dalam Shadow DOM, tetapi kemudian muncul pertanyaan tentang bagaimana gaya elemen-elemen tersebut dari luar, misalnya - jika mereka tidak digunakan oleh orang yang membuatnya. Jawaban atas pertanyaan ini cukup sederhana - elemen khusus ditata dengan cara yang sama seperti elemen bawaan.
my-custom-element { border-radius: 5px; width: 30%; height: 50%;
Perhatikan bahwa gaya eksternal lebih diutamakan daripada gaya yang dideklarasikan di dalam elemen, menimpanya.
Anda mungkin telah melihat bagaimana, ketika sebuah halaman ditampilkan di layar, pada titik tertentu Anda dapat mengamati konten yang tidak bergaya di dalamnya (inilah yang disebut FOUC - Flash Of Unstyled Content). Anda dapat menghindari fenomena ini dengan mengatur gaya untuk komponen yang tidak terdaftar, dan menggunakan beberapa efek visual saat mendaftarkannya. Untuk melakukan ini, Anda dapat menggunakan pemilih
:defined
. Anda dapat melakukan ini, misalnya, seperti ini:
my-button:not(:defined) { height: 20px; width: 50px; opacity: 0; }
Elemen tidak dikenal dan elemen pengguna tidak ditentukan
Spesifikasi HTML sangat fleksibel, memungkinkan Anda untuk mendeklarasikan setiap tag yang Anda butuhkan untuk pengembang. Dan, jika tag tidak dikenali oleh browser, itu akan diproses oleh parser sebagai
HTMLUnknownElement
:
var element = document.createElement('thisElementIsUnknown'); if (element instanceof HTMLUnknownElement) { console.log('The selected element is unknown'); }
Namun, ketika bekerja dengan elemen khusus, skema seperti itu tidak berlaku. , ? , ,
HTMLElement
.
var element = document.createElement('this-element-is-undefined'); if (element instanceof HTMLElement) { console.log('The selected element is undefined but not unknown'); }
HTMLElement
HTMLUnknownElement
, , , , - . , , , .
div
. .
Chrome 36+. API Custom Components v0, , , , . API, , β
. API Custom Elements v1 Chrome 54+ Safari 10.1+ ( ). Mozilla v50, , . , Microsoft Edge API. , , webkit. , , , β IE 11.
, , ,
customElements
window
:
const supportsCustomElements = 'customElements' in window; if (supportsCustomElements) {
:
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); }); }
Ringkasan
, :
- HTML- JavaScript-, , CSS-.
- HTML- ( , ).
- . , β JavaScript, HTML, CSS, , , .
- - (Shadow DOM, , , ).
- , .
- , .
,
Custom Elements v1 , , , , , .
Pembaca yang budiman! ?
