Komponen Web telah wujud sejak sekian lama, menjanjikan cara piawai untuk mencipta elemen tersuai yang boleh diguna semula. Jelas bahawa walaupun Komponen Web telah mencapai kemajuan yang ketara, masih terdapat beberapa kaveat yang mungkin dihadapi oleh pembangun semasa bekerja dengan mereka. Blog ini akan meneroka 10 daripada kaveat ini.
Jika anda memutuskan sama ada untuk menggunakan komponen web dalam projek anda atau tidak. Adalah penting untuk mempertimbangkan sama ada komponen web disokong sepenuhnya dalam rangka kerja pilihan anda atau anda mungkin menghadapi beberapa kaveat yang tidak menyenangkan.
Sebagai contoh untuk menggunakan komponen web dalam Angular, anda perlu menambahkan CUSTOM_ELEMENTS_SCHEMA pada import modul.
@NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA], }) export class MyModule {}
Masalah menggunakan CUSTOM_ELEMENTS_SCHEMA ialah Angular akan menarik diri daripada pemeriksaan jenis dan intellisense untuk elemen tersuai dalam templat. (lihat isu)
Untuk menyelesaikan masalah ini, anda boleh membuat komponen pembalut sudut.
Berikut ialah contoh rupanya.
@Component({ selector: 'some-web-component-wrapper', template: '<some-web-component [someProperty]="someClassProperty"></some-web-component> }) export class SomeWebComponentWrapper { @Input() someClassProperty: string; } @NgModule({ declarations: [SomeWebComponentWrapper], exports: [SomeWebComponentWrapper], schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class WrapperModule {}
Ini berfungsi tetapi bukan idea yang baik untuk menciptanya secara manual. Oleh kerana itu mencipta banyak penyelenggaraan dan kita boleh menghadapi masalah tidak segerak dengan api. Untuk membuat ini kurang membosankan. Kedua-dua Lit (lihat di sini) dan Stensil (lihat di sini) menyediakan cli untuk menciptanya secara automatik. Walau bagaimanapun, keperluan untuk mencipta komponen pembalut ini di tempat pertama adalah overhed tambahan. Jika rangka kerja pilihan anda menyokong komponen web dengan betul, anda tidak perlu membuat komponen pembungkus.
Contoh lain ialah dengan React. Sekarang React v19 baru dikeluarkan yang menangani isu ini. Walau bagaimanapun, jika anda masih menggunakan v18 cuma ambil perhatian bahawa v18 tidak menyokong sepenuhnya komponen web. Jadi berikut ialah beberapa isu yang mungkin anda hadapi semasa bekerja dengan komponen web dalam React v18. Ini diambil terus daripada dokumen Lit.
"React menganggap bahawa semua sifat JSX dipetakan kepada atribut elemen HTML dan tidak menyediakan cara untuk menetapkan sifat. Ini menyukarkan untuk menghantar data kompleks (seperti objek, tatasusunan atau fungsi) ke komponen web."
"React juga menganggap bahawa semua acara DOM mempunyai "sifat acara" yang sepadan (onclick, onmousemove, dll), dan menggunakannya dan bukannya memanggil addEventListener(). Ini bermakna untuk menggunakan komponen web yang lebih kompleks dengan betul, anda sering perlu menggunakan ref() dan kod imperatif."
Untuk React v18 Lit mengesyorkan menggunakan komponen pembungkusnya kerana mereka membetulkan isu dengan menetapkan sifat dan mendengar acara untuk anda.
Berikut ialah contoh komponen pembalut React menggunakan Lit.
import React from 'react'; import { createComponent } from '@lit/react'; import { MyElement } from './my-element.js'; export const MyElementComponent = createComponent({ tagName: 'my-element', elementClass: MyElement, react: React, events: { onactivate: 'activate', onchange: 'change', }, });
Penggunaan
<MyElementComponent active={isActive} onactivate={(e) => setIsActive(e.active)} onchange={handleChange} />
Nasib baik dengan React v19 anda tidak perlu membuat komponen pembungkus lagi. Yay!
Penggunaan Komponen Web dalam bahagian hadapan mikro telah mendedahkan cabaran yang menarik:
Satu masalah penting ialah sifat global Pendaftaran Elemen Tersuai:
Jika anda menggunakan bahagian hadapan mikro dan merancang untuk menggunakan komponen web untuk menggunakan semula elemen UI merentas setiap apl, kemungkinan besar anda akan menghadapi ralat ini.
@NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA], }) export class MyModule {}
Ralat ini berlaku apabila cuba mendaftarkan elemen tersuai dengan nama yang telah digunakan. Ini adalah perkara biasa dalam bahagian hadapan mikro kerana setiap apl dalam bahagian hadapan mikro berkongsi fail index.html yang sama dan setiap apl cuba menentukan elemen tersuai.
Terdapat cadangan untuk menangani perkara ini yang dipanggil Scoped Custom Element Registries tetapi tiada ETA jadi malangnya anda perlu menggunakan polyfill.
Jika anda tidak menggunakan polyfill, satu penyelesaian adalah dengan mendaftarkan elemen tersuai secara manual dengan awalan untuk mengelakkan konflik penamaan.
Untuk melakukan ini dalam Lit, anda boleh mengelak daripada menggunakan penghias @customElement yang mendaftarkan elemen tersuai secara automatik. Kemudian tambahkan sifat statik untuk tagName.
Sebelum ini
@Component({ selector: 'some-web-component-wrapper', template: '<some-web-component [someProperty]="someClassProperty"></some-web-component> }) export class SomeWebComponentWrapper { @Input() someClassProperty: string; } @NgModule({ declarations: [SomeWebComponentWrapper], exports: [SomeWebComponentWrapper], schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class WrapperModule {}
Selepas
import React from 'react'; import { createComponent } from '@lit/react'; import { MyElement } from './my-element.js'; export const MyElementComponent = createComponent({ tagName: 'my-element', elementClass: MyElement, react: React, events: { onactivate: 'activate', onchange: 'change', }, });
Kemudian dalam setiap apl anda mentakrifkan elemen tersuai dengan awalan nama apl.
<MyElementComponent active={isActive} onactivate={(e) => setIsActive(e.active)} onchange={handleChange} />
Kemudian untuk menggunakan elemen tersuai, anda akan menggunakannya dengan awalan baharu.
Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry': the name "foo-bar" has already been used with this registry
Ini berfungsi sebagai penyelesaian jangka pendek yang cepat, namun anda mungkin dapati ia bukanlah pengalaman pembangun yang terbaik, jadi anda disyorkan untuk menggunakan polifill Pendaftaran Elemen Tersuai Scoped.
Shadow DOM, sambil menyediakan enkapsulasi, datang dengan set cabarannya sendiri:
Shadow dom berfungsi dengan menyediakan enkapsulasi. Ia menghalang gaya daripada bocor daripada komponen. Ia juga menghalang gaya global daripada menyasarkan elemen dalam bayang bayangan komponen. Bagaimanapun gaya dari luar komponen masih boleh bocor masuk jika gaya tersebut diwarisi.
Ini contohnya.
@customElement('simple-greeting') export class SimpleGreeting extends LitElement { render() { return html`<p>Hello world!</p>`; } }
export class SimpleGreeting extends LitElement { static tagName = 'simple-greeting'; render() { return html`<p>Hello world!</p>`; } }
Apabila kami mengklik butang
komponen-a
[SimpleGreeting].forEach((component) => { const newTag = `app1-${component.tagName}`; if (!customElements.get(newTag)) { customElements.define(newTag, SimpleGreeting); } });
Memandangkan acara itu datang daripada komponen-b, anda mungkin berfikir bahawa sasarannya ialah komponen-b atau butang. Walau bagaimanapun, acara itu ditangguhkan supaya sasaran menjadi komponen-a.
Jadi, jika anda perlu tahu sama ada acara datang daripada
@NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA], }) export class MyModule {}
Ini kerana penghalaan dikendalikan oleh penyemak imbas bukan rangka kerja anda. Rangka kerja perlu campur tangan peristiwa ini dan mengendalikan penghalaan pada peringkat rangka kerja. Walau bagaimanapun, disebabkan peristiwa disasarkan semula dalam ruang bayangan, ini menjadikan rangka kerja lebih mencabar untuk berbuat demikian kerana ia tidak mempunyai akses mudah kepada elemen penambat.
Untuk menyelesaikan masalah ini, kami boleh menyediakan pengendali acara pada yang akan menghentikan penyebaran pada acara itu dan mengeluarkan acara baru. Acara baharu itu perlu berbuih dan digubah. Juga secara terperinci kami memerlukan akses
ke contoh yang boleh kita perolehi daripada e.currentTarget.
@Component({ selector: 'some-web-component-wrapper', template: '<some-web-component [someProperty]="someClassProperty"></some-web-component> }) export class SomeWebComponentWrapper { @Input() someClassProperty: string; } @NgModule({ declarations: [SomeWebComponentWrapper], exports: [SomeWebComponentWrapper], schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class WrapperModule {}
Dari segi penggunaan, anda boleh menyediakan pendengar acara global untuk mendengar acara ini dan mengendalikan penghalaan dengan memanggil fungsi penghalaan khusus rangka kerja.
Apabila membina komponen web. Anda boleh membuat keputusan untuk meletakkan komponen web lain atau menyarangkannya di dalam komponen web lain. Ini contohnya.
ikon berlubang
import React from 'react'; import { createComponent } from '@lit/react'; import { MyElement } from './my-element.js'; export const MyElementComponent = createComponent({ tagName: 'my-element', elementClass: MyElement, react: React, events: { onactivate: 'activate', onchange: 'change', }, });
ikon bersarang
<MyElementComponent active={isActive} onactivate={(e) => setIsActive(e.active)} onchange={handleChange} />
Jika anda memutuskan untuk menyarangkan komponen ini boleh menyukarkan lagi untuk menanyakan komponen bersarang. Terutamanya jika anda mempunyai pasukan QA yang perlu membuat ujian hujung ke hujung, kerana mereka perlu menyasarkan elemen tertentu pada halaman.
Contohnya untuk mengakses beberapa ikon, kita perlu mengakses beberapa sepanduk terlebih dahulu dengan mengambil shadowRoot itu kemudian buat pertanyaan baharu di dalam akar bayang itu.
Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry': the name "foo-bar" has already been used with this registry
Ini mungkin kelihatan mudah tetapi ia menjadi semakin sukar apabila komponen anda bersarang lebih dalam. Juga jika komponen anda bersarang ini boleh menjadikan kerja dengan petua alat lebih sukar. Terutamanya jika anda perlu menyasarkan elemen bersarang dalam supaya anda boleh menunjukkan petua alat di bawahnya.
Apa yang saya dapati ialah menggunakan slot menjadikan komponen kami lebih kecil dan lebih fleksibel yang juga lebih boleh diselenggara. Jadi lebih suka slot, elakkan bersarang shadow dom.
Slot menyediakan cara untuk mengarang elemen UI, tetapi ia mempunyai had dalam komponen web.
Pemilih ::slotted hanya terpakai kepada anak langsung slot, mengehadkan kegunaannya dalam senario yang lebih kompleks.
Ini contohnya.
@customElement('simple-greeting') export class SimpleGreeting extends LitElement { render() { return html`<p>Hello world!</p>`; } }
export class SimpleGreeting extends LitElement { static tagName = 'simple-greeting'; render() { return html`<p>Hello world!</p>`; } }
[SimpleGreeting].forEach((component) => { const newTag = `app1-${component.tagName}`; if (!customElements.get(newTag)) { customElements.define(newTag, SimpleGreeting); } });
Komponen web sering ketinggalan daripada rangka kerja popular seperti Vue, React, Svelte dan Solid dalam menggunakan ciri baharu dan amalan terbaik.
Ini mungkin disebabkan oleh fakta bahawa komponen web bergantung pada pelaksanaan dan piawaian penyemak imbas, yang boleh mengambil masa yang lebih lama untuk berkembang berbanding kitaran pembangunan pesat rangka kerja JavaScript moden.
Akibatnya, pembangun mungkin mendapati diri mereka menunggu keupayaan tertentu atau terpaksa melaksanakan penyelesaian yang tersedia dalam rangka kerja lain.
Beberapa contoh ini ialah Lit menggunakan CSS dalam JS sebagai pilihan lalai untuk penggayaan. Sudah lama diketahui bahawa CSS dalam rangka kerja JS mempunyai masalah prestasi
kerana mereka sering memperkenalkan overhed masa jalan tambahan. Jadi kami mula melihat CSS yang lebih baharu dalam rangka kerja JS yang bertukar kepada penyelesaian berasaskan masa jalan sifar.
CSS Lit dalam penyelesaian JS masih berasaskan masa jalan.
Contoh lain ialah dengan Isyarat. Pada masa ini tingkah laku lalai dalam Lit ialah kami menambah kereaktifan pada sifat kelas dengan menambahkan penghias @property.
Walau bagaimanapun, apabila sifat itu ditukar, ia akan mencetuskan keseluruhan komponen untuk dipaparkan semula. Dengan Isyarat hanya sebahagian daripada komponen yang bergantung pada isyarat akan dikemas kini.
Ini lebih cekap untuk bekerja dengan UI. Sangat cekap sehingga terdapat cadangan baharu (TC39) untuk menambahkannya pada JavaScript.
Kini Lit menyediakan pakej untuk menggunakan Isyarat tetapi ia bukan kereaktifan lalai apabila rangka kerja lain seperti Vue dan Solid telah melakukan ini selama bertahun-tahun.
Kami berkemungkinan besar tidak akan melihat Isyarat sebagai kereaktifan lalai untuk beberapa tahun lagi sehingga isyarat adalah selain daripada piawaian web.
Satu lagi contoh yang berkaitan dengan kaveat saya sebelum ini "9. Elemen berslot sentiasa berada dalam dom". Rich Harris, pencipta Svelte bercakap tentang perkara ini
dalam catatan blognya 5 tahun lalu bertajuk "Mengapa saya tidak menggunakan Komponen Web".
Dia bercakap tentang cara mereka menggunakan pendekatan piawaian web untuk cara kandungan berslot ditayangkan dengan penuh semangat dalam Svelte v2. Namun, mereka terpaksa menjauhinya
dalam Svelte 3 kerana ia merupakan titik kekecewaan yang besar bagi pembangun. Mereka menyedari bahawa kebanyakan masa anda mahu kandungan berslot dipaparkan dengan malas.
Saya boleh menghasilkan lebih banyak contoh seperti dalam komponen web tidak ada cara mudah untuk menghantar data ke slot apabila rangka kerja lain seperti Vuejs sudah mempunyai sokongan untuk ini. Tetapi perkara utama di sini ialah
komponen web kerana ia bergantung pada piawaian web menggunakan ciri yang jauh lebih perlahan daripada rangka kerja yang tidak bergantung pada piawaian web.
Dengan tidak bergantung pada piawaian web, kami boleh berinovasi dan menghasilkan penyelesaian yang lebih baik.
Komponen Web menawarkan cara yang hebat untuk mencipta elemen tersuai yang boleh diguna semula dan dikapsulkan. Walau bagaimanapun, seperti yang telah kami terokai, terdapat beberapa kaveat dan cabaran yang mungkin dihadapi oleh pembangun apabila bekerja dengan mereka. Seperti ketidakserasian rangka kerja, penggunaan dalam bahagian hadapan mikro, pengehadan Shadow DOM, isu dengan penyasaran semula acara, slot dan penggunaan ciri yang perlahan adalah semua bidang yang memerlukan pertimbangan yang teliti.
Walaupun menghadapi cabaran ini, faedah Komponen Web, seperti enkapsulasi sebenar, mudah alih dan kebebasan rangka kerja, menjadikannya alat yang berharga dalam pembangunan web moden. Memandangkan ekosistem terus berkembang, kita boleh mengharapkan untuk melihat penambahbaikan dan penyelesaian baharu yang menangani kaveat ini.
Bagi pembangun yang mempertimbangkan Komponen Web, adalah penting untuk menimbang kebaikan dan keburukan ini dan sentiasa mendapat maklumat tentang kemajuan terkini dalam bidang tersebut. Dengan pendekatan dan pemahaman yang betul, Komponen Web boleh menjadi tambahan yang hebat pada kit alat pembangunan anda.
Atas ialah kandungan terperinci Kaveat Yang Mungkin Anda Hadapi Semasa Bekerja Dengan Komponen Web. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!