Kelas dasar untuk membuat komponen web menggunakan lit-html
lit-element dapat diinstal melalui paket NPM elemen lit-HTML.
lit-element memungkinkan Anda membuat komponen web dengan template HTML yang diekspresikan dengan literal template javascript, dan secara efisien membuat dan merender ulang template tersebut ke DOM.
lit-element mencapai ini dengan mengintegrasikan Lit-HTML dan memiliki fitur berikut:
render()renderCallbackinvalidate()this atau merusakid di root bayangan menggunakan this.$(...)Demo dapat ditemukan di sini.
Sederhana Tulis kode html Anda menggunakan lit-html dengan membuat metode render() .
import { LitElement , html } from '/src/lit-element.js' ;
class HelloWorld extends LitElement {
render ( ) {
return html `
< div style =" font-weight: bold " > Hello World </ div >
` ;
}
}
customElements . define ( 'hello-world' , HelloWorld ) < hello-world > </ hello-world >id Setelah konten telah diberikan pertama kali (mis. Setelah connectedCallback() menembak), maka Anda dapat mengakses elemen di root bayangan dengan id menggunakan this.$(...) .
Dalam contoh di bawah ini, kami menyebut this.changeColor() setiap kali tombol ditekan, yang pada hasilnya mengakses DIV menggunakan this.$("wrapper") dan memodifikasi warna latar belakangnya.
class ColorMarker extends LitElement {
changeColor ( ) {
const color = Math . random ( ) . toString ( 16 ) . substr ( 2 , 6 ) ;
// Easily query the element by id:
this . $ ( "wrapper" ) . style . backgroundColor = `# ${ color } ` ;
}
render ( ) {
return html `
< style >
div {
background-color: yellow;
}
</ style >
< button on-click = ${ ( ) => this . changeColor ( ) } >
Change background color
</ button >
< div id =" wrapper " > < slot > </ slot > </ div >
` ;
}
}
customElements . define ( 'color-marker' , ColorMarker ) ; < color-marker > Horse </ color-marker > Dalam contoh ini kita akan menggunakan properti. Setiap properti yang ditentukan dalam properties() akan memastikan kontennya diserahkan kembali pada waktu yang tepat saat dimodifikasi.
Properti dapat memiliki nilai default dan bahkan dapat tercermin melalui atribut (perubahan berjalan dua arah). Alih-alih melakukan sihir dan mengonversi kasus setelah aturan khusus seperti upper-case vs upperCase , Anda malah mendefinisikan contoh nama atribut yang harus dicerminkan oleh properti, dan dengan demikian menghindari ambiguitas apa pun.
Catatan, saat menggunakan properti, Anda harus menyebutnya this.withProperties sebelum menggunakan elemen. Saat metode mengembalikan kelas itu sendiri, ini dapat dilakukan sebagai bagian dari customElements.define(...)
Catatan, nilai -nilai default atribut diatur dari atribut elemen itu sendiri (sekarang atau hilang) dan dengan demikian nilai default yang ditetapkan melalui 'nilai' diabaikan.
import { LitElement , html } from '/src/lit-element.js' ;
class HelloWorld extends LitElement {
static get properties ( ) {
return {
uppercase : {
type : Boolean ,
attrName : "uppercase"
}
}
}
render ( ) {
return html `
< style >
.uppercase {
text-transform: uppercase;
}
</ style >
< div id =" box " class$ =" ${ this . uppercase ? 'uppercase' : '' } " >
< slot > Hello World </ slot >
</ div >
` ;
}
}
customElements . define ( 'hello-world' , HelloWorld . withProperties ( ) ) ; < hello-world > </ hello-world >
< hello-world uppercase > ¡Hola, mundo! </ hello-world > Saat membuat elemen khusus, pola yang baik adalah menggunakan atribut alih -alih metode atau properti. Ini memungkinkan penggunaan elemen secara deklaratif seperti <my-dialog opened> .
Untuk elemen khusus yang hanya dikonsumsi secara internal di elemen khusus lainnya, seringkali lebih cepat hanya mengandalkan properti. Ini juga terjadi jika Anda perlu menyampaikan data kompleks seperti array atau objek.
Untuk memudahkan untuk bekerja dengan atribut, lit-html-element mendukung pemetaan antara atribut dan properti secara otomatis, hanya dengan mendefinisikan nama atribut yang harus dipetakan oleh properti dengan via attrName: .
Kehadiran atribut atau tidak (pada elemen) menghasilkan nilai aktual , yaitu. Atribut yang hilang untuk properti boolean, berarti properti akan false dan untuk semua jenis properti lainnya, undefined . Ini berarti bahwa ketika memetakan properti ke atribut, tidak ada yang namanya nilai default karena nilai selalu didefinisikan tergantung pada keberadaan, atau tidak, atribut. Ini berarti bahwa value: diabaikan saat attrName: hadir.
Nilai dikonversi menggunakan konstruktor tipe mereka, yaitu String(attributeValue) untuk String , Number(attributeValue) untuk Number , dll.
Boolean memiliki penanganan khusus untuk mengikuti pola platform web.
Dari standar HTML:
Kehadiran atribut boolean pada elemen mewakili nilai sebenarnya, dan tidak adanya atribut mewakili nilai palsu.
Jika atribut ada, nilainya harus menjadi string kosong atau nilai yang merupakan kecocokan case-tidak sensitif untuk nama kanonik atribut, tanpa spasi putih terkemuka atau tertinggal.
Array dan Object disempurnakan untuk atribut dan tidak memiliki penanganan khusus, sehingga nilai -nilai dikonversi menggunakan konstruktornya sebagai jenis nilai lainnya, kecuali boolean.
this diteruskan ke render () untuk Anda, yang lebih bersih. terutama saat merusak. Anda masih bisa merujuk mereka secara manual.
class RenderShorthand extends LitElement {
static get properties ( ) {
return {
greeting : {
type : String ,
value : "Hello"
}
}
}
render ( { greeting } ) {
return html ` ${ greeting } World!` ;
}
}
customElements . define ( 'render-shorthand' , RenderShorthand . withProperties ( ) ) ; Ketika salah satu properti di properties() berubah, lit-element akan secara otomatis membuat ulang. Hal yang sama berlaku untuk atribut yang dipetakan ke properti melalui attrName .
Jika Anda perlu merender ulang secara manual, Anda dapat memicu render ulang melalui panggilan untuk invalidate() . Ini akan menjadwalkan microtask yang akan membuat konten tepat sebelum requestAnimationFrame berikutnya.
Elemen khusus perlu ditingkatkan sebelum bekerja. Ini terjadi secara otomatis oleh browser ketika memiliki semua sumber daya yang dibutuhkan.
Ini berarti bahwa jika Anda melakukan elemen khusus yang tergantung pada elemen khusus lainnya dan menggunakan properti untuk aliran data, maka mengatur properti tersebut sebelum elemen ditingkatkan, berarti Anda akan berakhir membayangi properti lit-html-element , yang berarti bahwa pembaruan properti dan refleksi atribut tidak akan berfungsi seperti yang diharapkan.
Ada API whenAllDefined(result, container) untuk mengatasi masalah ini, dengan mengizinkan untuk menunggu sampai semua dependensi telah ditingkatkan. Salah satu cara untuk menggunakannya adalah menimpa renderCallback() :
renderCallback ( ) {
if ( "resolved" in this ) {
super . renderCallback ( ) ;
} else {
whenAllDefined ( this . render ( this ) ) . then ( ( ) => {
this . resolved = true ;
this . renderCallback ( ) ;
} ) ;
}
}Tetapi Anda mungkin masih berhasil membayangi properti jika Anda mengatur nilai sebelum ditingkatkan seperti
document . getElementById ( 'ninja' ) . firstName = "Ninja" ;Jadi jaga ini dengan cara berikut:
customElements . whenDefined ( 'computed-world' ) . then ( ( ) => {
document . getElementById ( 'ninja' ) . firstName = "Ninja" ;
} ) ;Jika Anda memerlukan beberapa properti yang dihitung dan pembaruan tergantung pada properti lain, itu mungkin menggunakan nilai 'dihitung', yang mendefinisikan metode objek dengan argumen sebagai string.
Properti yang dihitung hanya memperbarui ketika semua properti dependen didefinisikan . Nilai default dapat diatur menggunakan value:
Catatan, properti yang dihitung tidak dapat dipantulkan ke atribut.
Misalnya.
import { LitElement , html } from '/node_modules/lit-html-element/lit-element.js' ;
class ComputedWorld extends LitElement {
static get properties ( ) {
return {
firstName : {
type : String ,
attrName : "first-name"
} ,
doubleMessage : {
type : String ,
computed : 'computeDoubleMessage(message)'
} ,
message : {
type : String ,
computed : 'computeMessage(firstName)' ,
value : 'Hej Verden'
}
}
}
computeDoubleMessage ( message ) {
return message + " " + message ;
}
computeMessage ( firstName ) {
return `Konichiwa ${ firstName } ` ;
}
render ( ) {
return html `
< div style =" font-weight: bold " > ${ this . doubleMessage } </ div >
` ;
}
}
customElements . define ( 'computed-world' , ComputedWorld . withProperties ( ) ) < computed-world > </ computed-world >
< computed-world first-name =" Kenneth " > </ computed-world > Dimungkinkan untuk menggunakan lit-html-element dari naskah bukan javascript. Saat menggunakan TypeScript, Anda dapat memilih menggunakan dekorator alih -alih mendefinisikan properti statis Accessor static get properties() .
Saat menggunakan dekorator properti, apa pun, aksesor properti statis seperti itu akan diabaikan, dan Anda juga tidak perlu menelepon .withProperties() .
import {
LitElement ,
html ,
TemplateResult ,
customElement ,
property ,
attribute ,
computed
} from '../../src/lit-element.js' ;
@ customElement ( 'test-element' )
export class TestElement extends LitElement {
@ computed ( 'firstName' , 'lastName' )
get fullName ( ) : string {
return ` ${ this . firstName } ${ this . lastName } ` ;
}
@ property ( ) firstName : string = 'John' ;
@ property ( ) lastName : string = 'Doe' ;
@ property ( ) human : boolean = true ;
@ property ( ) favorite : any = { fruit : 'pineapple' } ;
@ property ( ) kids : Array < string > = [ 'Peter' , 'Anna' ] ;
@ attribute ( 'mother' ) mother : string ;
@ attribute ( 'super-star' ) superStar : boolean ;
render ( ) : TemplateResult {
return html `
< h2 > Name: ${ this . fullName } </ h2 >
< h2 > Is human?: ${ human ? "yup" : "nope" } </ h2 >
< h2 > Favorites: ${ JSON . stringify ( this . favorite ) } </ h2 >
< h2 > Kids: ${ JSON . stringify ( this . kids ) } </ h2 >
< h2 > Mother: ' ${ this . mother } ' </ h2 >
< h2 > Superstar?: ' ${ this . superStar } ' </ h2 >
` ;
}
} < test-element super-star mother =" Jennifer " > </ test-element > Untuk menggunakan dekorator dari TypeScript, Anda perlu mengaktifkan pengaturan kompiler experimentalDecorators di tsconfig.json Anda atau menggunakan bendera --experimentalDecorators .
{
"compilerOptions" : {
"experimentalDecorators" : true
}
}Dengan diaktifkan di atas, Anda dapat mulai menggunakan dekorator tetapi harus menentukan informasi jenis secara manual:
@ property ( { type : String } )
myProperty: string ;Karena jenisnya sering dapat berasal dari properti, terutama di TypeScript di mana Anda menentukan jenisnya, ini terasa seperti sedikit pekerjaan ganda. Untungnya ada proposal spesifikasi baru yang disebut refleksi metadata yang bertujuan menyelesaikan masalah ini. Proposal ini belum diusulkan secara resmi ke kelompok kerja TC39 (mendefinisikan standar JavaScript) tetapi sudah ada polyfill kerja yang tersedia dan dukungan eksperimental dalam TypeScript.
Dengan refleksi metadata yang diaktifkan dimungkinkan untuk mendefinisikan jenis properti secara lebih ringkas:
@ property ( ) myProperty: string ;Untuk menggunakan dekorator dari TypeScript, ikuti langkah -langkah berikut.
emitDecoratorMetadata di tsconfig.json Anda atau menggunakan bendera --emitDecoratorMetadata . {
"compilerOptions" : {
"emitDecoratorMetadata" : true
}
}$ npm install --save-dev rbuckton/reflect-metadata < script src =" /node_modules/reflect-metadata/Reflect.js " > </ script >Dokumentasi API berikut menggunakan Web IDL.
PropertyOptions properti statis PropertyOptions digunakan untuk mengkonfigurasi properti untuk elemen khusus. Dalam JavaScript Anda perlu mengimplementasikan properti statis yang disebut properties , yang mengembalikan objek di mana setiap properti dari objek tersebut memiliki PropertyOptions yang terkait:
class {
static get properties ( ) {
return { selfDefinedObjectProperty : ... }
}
} Kamus PropertyOptions memiliki 4 properti opsional, ditunjukkan di bawah ini dalam format Web IDL.
typedef (BooleanConstructor or DateConstructor or NumberConstructor or StringConstructor or ArrayConstructor or ObjectConstructor) PropertyType ;
dictionary PropertyOptions {
attribute PropertyType type ;
attribute any value ;
attribute USVString attrName ;
attribute USVString computed ;
}type Properti type hanya opsional saat menggunakan dekorator dan refleksi metadata.
value Properti value mendefinisikan nilai default untuk properti. Dalam hal atribut / pemetaan properti melalui attrName (lihat di bawah), value diabaikan. Saat menggunakan dekorator, nilainya mengambil dari definisi properti itu sendiri:
@ property ( ) myProperty: string = "Hello World" ; attrName attrName mendefinisikan nama atribut yang harus tercermin dengan properti dan sebaliknya. Dengan attrName , nilai default diabaikan dan ditentukan dari elemen khusus sebagai gantinya, yaitu. tergantung pada keberadaan atau tidak dari atribut.
Nama atribut, banyak dalam huruf Latin (AZ) termasuk '-' (Hyphen). Semua atribut pada elemen HTML dalam dokumen HTML mendapatkan ASCII-Lowercased secara otomatis, dan tanda hubung awal ('-') diabaikan.
Ketahuilah bahwa atribut data, yaitu. Atribut yang dimulai dengan data- dapat diakses sebagai properti secara otomatis melalui element.dataset .
Ketika properti yang dipetakan diatur pada elemen, atribut akan diperbarui dengan representasi string dari nilai baru, kecuali nilai baru undefined di mana atribut akan dihapus.
Ada satu pengecualian untuk ini, sebagai sifat boolean yang tercermin secara berbeda. Mengatur properti ke true dan atribut (katakanlah attr ) diatur ke string kosong '' (Atribut makna ada, yaitu. <div attr> ). Mengatur properti ke false dan atribut dihapus, yaitu. <div> .
Ketika atribut diatur, nilainya dikonversi menggunakan konstruktor tipe mereka, yaitu String(attributeValue) untuk String , Number(attributeValue) untuk Number , dll.
Boolean memiliki penanganan khusus untuk mengikuti pola platform web.
Dari standar HTML:
Kehadiran atribut boolean pada elemen mewakili nilai sebenarnya, dan tidak adanya atribut mewakili nilai palsu.
Jika atribut ada, nilainya harus menjadi string kosong atau nilai yang merupakan kecocokan case-tidak sensitif untuk nama kanonik atribut, tanpa spasi putih terkemuka atau tertinggal.
Baca lebih lanjut di bagian refleksi atribut di atas.
computed Properti dapat dihitung dari properti lain menggunakan computed , dibutuhkan string seperti 'methodName(property1, property2)' , di mana methodName adalah metode pada elemen dan property1 dan property2 didefinisikan.
Properti yang dihitung hanya memperbarui ketika semua properti dependen didefinisikan . Nilai default dapat diatur menggunakan value:
Catatan, properti yang dihitung tidak dapat dipantulkan ke atribut.
renderCallback renderCallback memungkinkan untuk kait khusus sebelum dan sesudah rendering.
Jika Anda perlu melakukan pekerjaan tambahan sebelum rendering, seperti mengatur properti berdasarkan properti lain, subclass dapat mengganti renderCallback() untuk melakukan pekerjaan sebelum atau setelah kelas dasar memanggil render() , termasuk mengatur properti dependen sebelum render() .
withProperties()TODO:
render(HTMLElement this)TODO: Pindah dokumen ke sini
async invalidate()TODO: Pindah dokumen ke sini
$(DOMString id)TODO: Pindah dokumen ke sini
whenAllDefined(TemplateResult result)TODO: Pindah dokumen ke sini
@customElement(USVString tagname)Dekorator kelas untuk mendaftarkan elemen khusus
@ customElement ( 'my-element' )
class extends HTMLElement {
...
}@property(optional PropertyOptions options) Dekorator properti untuk mengaitkan ke dalam sistem properti lit-html-element .
Saat menggunakan dekorator properti, Anda tidak perlu mendefinisikan properti statis Accessor static get properties() .
Saat menggunakan dekorator properti, apa pun, aksesor properti statis seperti itu akan diabaikan, dan Anda juga tidak perlu menelepon .withProperties() .
@ property ( { type : String } )
myProperty: string ;Periksa ekstensi untuk TypeScript untuk info lebih lanjut.
@attribute(USVString attrName) Dekorator properti untuk mengaitkan ke dalam sistem properti lit-html-element dan mengaitkan properti dengan atribut elemen khusus.
Periksa properti attrName untuk info lebih lanjut.
@computed(any dependency1, any dependency2, ...) Dekorator properti untuk mengaitkan ke dalam sistem properti lit-html-element dan membuat properti yang dihitung secara otomatis dari properti lain.
Periksa properti computed untuk info lebih lanjut.
@listen(USVString eventName, (USVString or EventTarget) target) Dekorator metode untuk menambahkan pendengar acara. Anda dapat menggunakan string untuk target dan itu akan mencari elemen di shadowroot dengan id itu.
Pendengar acara ditambahkan setelah rendering pertama, yang menciptakan Shadow Dom.