Pada satu titik saya harus segera berkenalan dengan komponen web dan menemukan cara untuk mengembangkannya dengan mudah. Saya berencana untuk menulis serangkaian artikel yang akan
entah bagaimana mengatur pengetahuan komponen web, elemen lit dan memberikan pengantar singkat tentang teknologi ini untuk orang lain. Saya bukan ahli dalam teknologi ini dan dengan senang hati akan menerima umpan balik.
lit-element adalah pembungkus (template dasar) untuk komponen web asli. Ini mengimplementasikan banyak metode mudah yang tidak ada dalam spesifikasi. Karena kedekatannya dengan implementasi asli, lit-elemen menunjukkan hasil yang sangat baik dalam berbagai tolok ukur relatif terhadap pendekatan lain (pada 02/06/2019).
Bonus yang saya lihat dari penggunaan elemen-lit sebagai kelas dasar komponen web:
- Teknologi ini sudah mengimplementasikan versi kedua dan "sakit dengan penyakit anak-anak", yang khas pada instrumen yang baru saja muncul.
- Perakitan dapat dilakukan baik polimer, dan webpack, naskah, rollup, dll., Ini memungkinkan Anda untuk menanamkan elemen lit dalam setiap proyek modern tanpa masalah.
- Elemen lit memiliki sistem yang sangat nyaman untuk bekerja dengan properti dalam hal mengetik, menginisiasi dan mengonversi nilai.
- elemen lit mengimplementasikan logika yang hampir sama dengan reaksi, mis. ia menyediakan sangat minimum - satu templat untuk membangun komponen dan renderingnya dan tidak membatasi pengembang dalam memilih ekosistem dan perpustakaan tambahan.
Buat komponen web sederhana pada elemen-lit. Mari kita beralih ke dokumentasi. Kami membutuhkan yang berikut:
- Tambahkan paket npm dengan elemen lit ke perakitan kami
npm install --save lit-element
- Buat komponen kami.
Sebagai contoh, kita perlu membuat komponen web yang diinisialisasi dalam tag my-component
. Untuk melakukan ini, buat file js my-component.js
dan tentukan template dasarnya:
Pertama, kami mengimpor template dasar kami:
import { LitElement, html } from 'lit-element';
Kedua, buat komponen web itu sendiri menggunakan LitElement
Dan yang terakhir adalah mendaftarkan komponen web di browser
customElements.define('my-component', MyComponent);
Hasilnya, kami mendapatkan yang berikut:
import { LitElement, html } from 'lit-element'; class MyComponent extends LitElement { render() { return html`<p>Hello World!</p>` } } customElements.define('my-component', MyComponent);
Jika Anda mengecualikan kebutuhan untuk menghubungkan my-component.js
ke html, maka itu saja. Komponen paling sederhana sudah siap.
Saya mengusulkan untuk tidak menemukan kembali roda dan mengambil perakitan selesai lit-elemen-build-rollup. Ikuti instruksi:
git clone https://github.com/PolymerLabs/lit-element-build-rollup.git cd lit-element-build-rollup npm install npm run build npm run start
Setelah semua perintah selesai, kita pergi ke halaman di browser http: // localhost: 5000 / .
Jika kita melihat dalam html, kita akan melihat bahwa webcomponents-loader.js ada di depan tag penutup. Ini adalah seperangkat polyfill untuk komponen web, dan untuk operasi lintas-browser dari komponen web itu diinginkan bahwa polyfill ini ada. Mari kita lihat tabel browser yang menerapkan semua standar untuk bekerja dengan komponen web, ia mengatakan bahwa EDGE masih belum sepenuhnya menerapkan standar (saya diam tentang IE11, yang masih harus didukung).

Diimplementasikan 2 opsi untuk polyfill ini:
- webcomponents-bundle.js - versi ini berisi semua opsi yang memungkinkan untuk polyfill, semuanya dimulai, tetapi setiap polyfill hanya akan bekerja berdasarkan tanda-tanda yang terdeteksi.
- webcomponents-loader.js adalah bootloader minimal yang, berdasarkan gejala yang terdeteksi, memuat polyfill yang diperlukan
Saya juga meminta Anda untuk memperhatikan polyfill lain - custom-elements-es5-adapter.js . Menurut spesifikasi, hanya kelas ES6 yang dapat ditambahkan ke customElements.define asli. Untuk kinerja terbaik, kode ES6 harus diteruskan hanya ke browser yang mendukungnya, dan ES5 untuk semua orang. Ini tidak selalu mungkin dilakukan, oleh karena itu, untuk kompatibilitas lintas-browser yang lebih baik, disarankan agar semua kode ES6 dikonversi ke ES5. Tetapi dalam hal ini, komponen web pada ES5 tidak akan dapat bekerja di browser. Untuk mengatasi masalah ini, ada custom-elements-es5-adapter.js.
Sekarang mari kita buka file ./src/my-element.js
import {html, LitElement, property} from 'lit-element'; class MyElement extends LitElement {
Mesin template lit-html dapat memproses string secara berbeda. Saya akan memberi Anda beberapa opsi:
Kiat untuk mengoptimalkan fungsi render ():
- tidak boleh mengubah status elemen,
- seharusnya tidak memiliki efek samping,
- seharusnya hanya bergantung pada properti elemen,
- harus mengembalikan hasil yang sama saat mentransmisikan nilai yang sama.
Jangan perbarui DOM di luar fungsi render ().
Lit-html bertanggung jawab untuk merender elemen-lit - ini adalah cara deklaratif untuk menggambarkan bagaimana komponen web harus ditampilkan. lit-html menjamin pembaruan cepat dengan hanya mengubah bagian-bagian DOM yang perlu diubah.
Hampir semua kode ini dalam contoh sederhana, tetapi dekorator @property
properti ditambahkan untuk properti myProp
. Dekorator ini menunjukkan bahwa kami mengharapkan atribut bernama myprop
di my-element
. Jika tidak ada atribut yang ditetapkan, nilai string diatur ke stuff
secara default.
<my-element></my-element> <my-element myprop="else"></my-element>
elemen lit menyediakan 2 cara untuk bekerja dengan property
:
- Melalui dekorator.
- Melalui
properties
pengambil statis.
Opsi pertama memungkinkan untuk menentukan setiap properti secara terpisah:
@property({type: String}) prop1 = ''; @property({type: Number}) prop2 = 0; @property({type: Boolean}) prop3 = false; @property({type: Array}) prop4 = []; @property({type: Object}) prop5 = {};
Yang kedua adalah menentukan segalanya di satu tempat, tetapi dalam kasus ini, jika properti memiliki nilai default, itu harus ditulis dalam metode konstruktor kelas:
static get properties() { return { prop1: {type: String}, prop2: {type: Number}, prop3: {type: Boolean}, prop4: {type: Array}, prop5: {type: Object} }; } constructor() { this.prop1 = ''; this.prop2 = 0; this.prop3 = false; this.prop4 = []; this.prop5 = {}; }
API untuk bekerja dengan properti dalam elemen lit cukup luas:
- atribut : apakah suatu properti dapat menjadi atribut yang dapat diamati. Jika
false
, maka atribut akan dikeluarkan dari pengamatan, tidak ada pengambil akan dibuat untuk itu. Jika true
atau attribute
ada, maka properti yang ditentukan dalam pengambil dalam format lowerCamelCase akan sesuai dengan atribut dalam format string. Jika sebuah string ditentukan, misalnya my-prop
, maka string tersebut akan sesuai dengan nama yang sama dalam atribut. - konverter : berisi deskripsi tentang cara mengkonversi nilai dari / ke atribut / properti. Nilai dapat berupa fungsi yang berfungsi untuk membuat cerita bersambung dan membatalkan nilai, atau dapat berupa objek dengan kunci
toAttribute
dan toAttribute
, kunci ini berisi fungsi terpisah untuk mengonversi nilai. Secara default, properti berisi konversi ke tipe dasar Boolean
, String
, Number
, Object
dan Array
. Aturan konversi tercantum di sini . - type : menunjukkan salah satu tipe dasar yang akan dimiliki properti ini. Ini digunakan sebagai "petunjuk" untuk konverter tentang jenis properti yang seharusnya mengandung.
- mencerminkan : menunjukkan apakah atribut harus dikaitkan dengan properti (
true
) dan diubah sesuai dengan aturan dari type
dan converter
. - hasChanged : masing-masing properti memilikinya, berisi fungsi yang menentukan apakah ada perubahan antara nilai lama dan baru, masing-masing mengembalikan
Boolean
. Jika true
, itu mulai memperbarui item. - noAccessor : properti ini menerima
Boolean
dan default ke false
. Ini melarang generasi getter dan setter untuk setiap properti untuk mengaksesnya dari kelas. Ini tidak membatalkan konversi.
Mari kita membuat contoh hipotetis: kita akan menulis komponen web yang berisi parameter yang berisi string, kata ini harus digambar di layar, di mana setiap huruf lebih besar dari yang sebelumnya.
<ladder-of-letters letters=""></ladder-of-letters>
pada akhirnya kita dapatkan:

ketika tombol diklik, properti diubah, yang menyebabkan cek pertama, dan kemudian dikirim untuk menggambar ulang.

dan menggunakan reflect
kita juga bisa melihat perubahan html

Jika Anda mengubah atribut ini dengan kode di luar komponen web ini, kami juga akan menyebabkan redraw komponen web.
Sekarang perhatikan styling komponen. Kami memiliki 2 cara untuk gaya elemen lit:
- Styling dengan menambahkan tag gaya ke metode render
render() { return html` <style> p { color: green; } </style> <p>Hello World</p> `; }

- Melalui
styles
pengambil statis
import {html, LitElement, css} from 'lit-element'; class MyElement extends LitElement { static get styles() { return [ css` p { color: red; } ` ]; } render() { return html` <p>Hello World</p> `; } } customElements.define('my-element', MyElement);
Akibatnya, kami mendapatkan bahwa tag dengan gaya tidak dibuat, tetapi ditulis ( >= Chrome 73
) di Shadow DOM
elemen sesuai dengan spesifikasi . Ini meningkatkan kinerja dengan sejumlah besar elemen, karena ketika mendaftarkan komponen baru, dia sudah tahu sifat apa yang ditentukan gayanya, mereka tidak perlu didaftarkan setiap waktu dan diceritakan kembali.

Selain itu, jika spesifikasi ini tidak didukung, maka tag style
reguler dibuat di komponen.

Plus, jangan lupa bahwa dengan cara ini kita juga dapat memisahkan gaya mana yang akan ditambahkan dan dihitung pada halaman. Misalnya, untuk menggunakan kueri media tidak dalam css, tetapi di JS dan hanya menerapkan gaya yang diinginkan, misalnya (ini liar, tetapi harus):
static get styles() { const mobileStyle = css`p { color: red; }`; const desktopStyle = css`p { color: green; }`; return [ window.matchMedia("(min-width: 400px)").matches ? desktopStyle : mobileStyle ]; }
Dengan demikian, kita akan melihat ini jika pengguna masuk ke perangkat dengan lebar layar lebih dari 400px.

Dan ini adalah jika pengguna mengunjungi situs dari perangkat dengan lebar kurang dari 400px.

Pendapat saya: praktis tidak ada kasus yang memadai ketika pengguna, bekerja pada perangkat mobile, tiba-tiba menghadapi monitor penuh dengan lebar layar 1920px. Tambahkan ke ini pemuatan komponen yang malas. Hasilnya, kami mendapatkan bagian depan yang sangat optimal dengan rendering komponen yang cepat. Satu-satunya masalah adalah kesulitan dalam mendukung.
Sekarang saya mengusulkan untuk berkenalan dengan metode siklus hidup elemen lit:
- render () : mengimplementasikan deskripsi elemen DOM menggunakan
lit-html
. Idealnya, fungsi render
adalah fungsi murni yang hanya menggunakan properti elemen saat ini. Metode render()
dipanggil oleh fungsi update()
. - shouldUpdate (changedProperties) : diimplementasikan jika perlu untuk mengontrol pembaruan dan rendering, ketika properti diubah atau
requestUpdate()
dipanggil. Argumen ke fungsi changedProperties
adalah Map
berisi kunci untuk properti yang diubah. Secara default, metode ini selalu mengembalikan true
, tetapi logika metode ini dapat diubah untuk mengontrol pembaruan komponen. - performUpdate () : diterapkan untuk mengontrol waktu pembaruan, misalnya, untuk berintegrasi dengan penjadwal.
- pembaruan (ubahProperti) : metode ini memanggil
render()
. Itu juga memperbarui atribut elemen sesuai dengan nilai properti. Mengatur properti di dalam metode ini tidak akan menyebabkan pembaruan lain. - firstUpdated (changedProperties) : dipanggil setelah pembaruan pertama elemen DOM segera sebelum panggilan yang
updated()
. Metode ini dapat berguna untuk mengambil tautan ke simpul statis yang divisualisasikan yang perlu Anda kerjakan secara langsung, misalnya, dalam updated()
. - updated (changedProperties) : dipanggil setiap kali DOM item diperbarui dan ditampilkan. Implementasi untuk melakukan tugas setelah memperbarui melalui DOM API, misalnya, berfokus pada elemen.
- requestUpdate (name, oldValue) : mengaktifkan permintaan pembaruan asinkron untuk suatu item. Ini harus dipanggil ketika item perlu diperbarui berdasarkan beberapa negara bukan disebabkan oleh pengaturan properti.
- createRenderRoot () : secara default membuat Shadow Root untuk item. Jika penggunaan Shadow DOM tidak diperlukan, maka metode harus mengembalikan
this
.
Bagaimana cara pembaruan elemen:
- Properti diberi nilai baru.
- Jika properti
hasChanged(value, oldValue)
mengembalikan false
, item tidak diperbarui. Kalau tidak, pembaruan direncanakan dengan memanggil requestUpdate()
. - requestUpdate () : memperbarui elemen setelah microtask (di akhir loop acara dan sebelum redraw berikutnya).
- performUpdate () : pembaruan sedang berlangsung, dan berlanjut dengan sisa pembaruan API.
- shouldUpdate (changedProperties) : pembaruan berlanjut jika
true
dikembalikan. - firstUpdated (berubahProperti) : dipanggil saat item diperbarui untuk pertama kalinya, segera sebelum menelepon
updated()
. - perbarui (ubahProperti) : memperbarui item. Mengubah properti dalam metode ini tidak menyebabkan pembaruan lain.
- render () : mengembalikan template
lit-html
untuk merender elemen dalam DOM. Mengubah properti dalam metode ini tidak menyebabkan pembaruan lain.
- updated (changedProperties) : dipanggil setiap kali suatu item diperbarui.
Untuk memahami semua nuansa siklus hidup komponen, saya sarankan Anda untuk membaca dokumentasi .
Di tempat kerja, saya memiliki proyek pada adobe experience manager (AEM), dalam pembuatannya pengguna dapat menyeret dan melepaskan komponen ke halaman, dan menurut ideologi AEM, komponen ini berisi tag script
yang berisi semua yang diperlukan untuk mengimplementasikan logika komponen ini. Namun pada kenyataannya, pendekatan ini memunculkan banyak sumber daya yang menghalangi dan kesulitan dengan implementasi front dalam sistem ini. Untuk mengimplementasikan bagian depan, komponen web dipilih sebagai cara untuk tidak mengubah rendering sisi server (yang ia lakukan dengan sangat baik), serta untuk memperkaya implementasi lama dengan pendekatan baru dengan lembut, bitwise. Menurut pendapat saya, ada beberapa opsi untuk menerapkan pemuatan komponen web untuk sistem ini: kumpulkan bundel (dapat menjadi sangat besar) atau pecah menjadi beberapa bagian (banyak file kecil, pemuatan dinamis diperlukan), atau gunakan pendekatan saat ini dengan menyematkan skrip di setiap komponen yang diberikan di sisi server (saya benar-benar tidak ingin kembali ke ini). Menurut saya, opsi pertama dan ketiga bukanlah opsi. Untuk yang kedua, Anda memerlukan bootloader dinamis, seperti pada stensil. Tetapi untuk elemen lit dalam "kotak" ini tidak disediakan. Ada upaya dari pengembang elemen lit untuk membuat loader dinamis , tetapi ini adalah percobaan, dan tidak disarankan untuk menggunakannya dalam produksi. Juga dari pengembang elemen lit ada masalah dalam repositori spesifikasi komponen web dengan proposal untuk menambah spesifikasi kemampuan untuk secara dinamis memuat js yang diperlukan untuk komponen web berdasarkan markup html pada halaman. Dan, menurut pendapat saya, alat asli ini adalah ide yang sangat bagus yang akan memungkinkan Anda untuk membuat satu titik inisialisasi komponen web dan cukup menambahkannya ke semua halaman situs.
Untuk memuat komponen web elemen lit secara dinamis dengan orang-orang PolymerLabs, elemen-split dikembangkan. Ini adalah solusi eksperimental. Ini bekerja dengan cara berikut:
- Untuk membuat SplitElement, Anda menulis dua definisi elemen dalam dua modul.
- Salah satunya adalah sebuah rintisan, yang mendefinisikan bagian-bagian yang dimuat dari suatu elemen: biasanya ini adalah nama dan properti. Properti harus didefinisikan dengan sebuah rintisan sehingga elemen-lit dapat menghasilkan atribut yang dapat diamati secara tepat waktu untuk memanggil
customElements.define()
. - Stub juga harus memiliki metode beban asinkron statis yang mengembalikan kelas implementasi.
- Kelas lain adalah "implementasi", yang berisi segalanya.
- Konstruktor
SplitElement
memuat kelas implementasi dan menjalankan upgrade()
.
Contoh rintisan:
import {SplitElement, property} from '../split-element.js'; export class MyElement extends SplitElement {
Contoh Implementasi:
import {MyElement} from './my-element.js'; import {html} from '../split-element.js';
Contoh SplitElement pada ES6:
import {LitElement, html} from 'lit-element'; export * from 'lit-element';
Jika Anda masih menggunakan rakitan yang disarankan di atas pada Rollup, pastikan untuk mengatur babel agar dapat menangani impor dinamis
npm install @babel/plugin-syntax-dynamic-import
Dan dalam pengaturan .babelrc tambahkan
{ "plugins": ["@babel/plugin-syntax-dynamic-import"] }
Di sini saya membuat contoh kecil implementasi komponen web dengan pemuatan yang tertunda: https://github.com/malay76a/elbrus-split-litelement-web-components
Saya mencoba menerapkan pendekatan pemuatan dinamis komponen web, sampai pada kesimpulan berikut: alat ini cukup berfungsi, Anda perlu mengumpulkan semua definisi komponen web dalam satu file, dan menghubungkan deskripsi komponen itu sendiri melalui potongan secara terpisah. Tanpa http2, pendekatan ini tidak berfungsi, karena Kumpulan besar file-file kecil yang menggambarkan komponen terbentuk. Berdasarkan prinsip desain atom , impor atom harus ditentukan dalam tubuh, tetapi tubuh harus sudah terhubung sebagai komponen terpisah. Salah satu hambatannya adalah bahwa pengguna akan menerima banyak definisi elemen pengguna di browser yang akan diinisialisasi dengan satu atau lain cara di browser dan keadaan awal akan ditentukan. Solusi semacam itu berlebihan. Salah satu opsi untuk solusi sederhana untuk pemuat komponen adalah algoritma berikut:
- memuat utilitas yang diperlukan,
- memuat polyfill,
- merakit elemen khusus dari DOM cahaya:
- semua elemen DOM yang mengandung tanda hubung dalam nama tag dipilih
- daftar disaring dan daftar dibentuk dari elemen pertama.
- :
- Intersection Observer,
- +- 100px import.
- 3 shadowDOM,
- , shadowDOM , , import JS.
- lit-element open-wc.org . webpack rollup, - storybook, IDE.
:
- Let's Build Web Components! Part 5: LitElement
- Web Component Essentials
- A night experimenting with Lit-HTML…
- LitElement To Do App
- LitElement app tutorial part 1: Getting started
- LitElement tutorial part 2: Templating, properties, and events
- LitElement tutorial part 3: State management with Redux
- LitElement tutorial part 4: Navigation and code splitting
- LitElement tutorial part 5: PWA and offline
- Lit-html workshop
- Awesome lit-html