使用LIT-HTML創建Web組件的基類
可以通過LIT-HTML元素NPM軟件包安裝lit-element 。
lit-element使您可以使用用JavaScript模板文字表示的HTML模板創建Web組件,並有效地渲染並將這些模板重新呈現為DOM。
通過集成LIT-HTML, lit-element可以實現這一目標,並具有以下功能:
render()方法易於渲染renderCallback可能會預/填充掛鉤invalidate()來手動觸發重新渲染this或破壞的訪問屬性和方法id的ID元素this.$(...)演示可以在這裡找到。
簡單地使用lit-html創建render()方法來編寫HTML代碼。
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查詢元素在第一次渲染內容(即connectedCallback() fires)之後,您可以使用id訪問Shadow root中的元素this.$(...) 。
在下面的示例中,每當按下按鈕時,我們將調用this.changeColor() ,結果使用this.$("wrapper")並修改其背景顏色。
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 >在此示例中,我們將使用屬性。靜態getter properties()中定義的每個屬性都將確保在修改時在正確的時間重新渲染內容。
屬性可以具有默認值,甚至可以通過屬性反映(更改是雙向的)。與其在諸如upper-case與upperCase的特殊規則之後進行魔術和轉換案例,而是定義了該屬性應反映的屬性名稱的示例,從而避免任何歧義。
注意,使用屬性時,必須在使用元素之前調用this.withProperties 。隨著該方法返回類本身,可以作為customElements.define(...)
注意,屬性默認值是從元素屬性本身(現在或丟失)設置的,因此忽略了通過“值”設置的默認值。
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 > 創建自定義元素時,一個好的模式是使用屬性代替方法或屬性。這允許聲明使用元素,就像<my-dialog opened>一樣。
對於僅在其他自定義元素中消耗的自定義元素,它通常僅依靠屬性更快。如果您需要傳遞複雜數據,例如數組或對象,也是如此。
為了使使用屬性易於使用, lit-html-element僅通過定義屬性的名稱應使用attrName: 。
屬性是否存在(在元素上)導致實際值,即。布爾屬性的缺失屬性意味著該屬性將是false ,並且對於所有其他屬性類型undefined 。這意味著,當將屬性映射到屬性時,沒有默認值始終根據屬性的存在而定義為默認值。這意味著設置value:當attrName:存在時被忽略。
使用其類型構造函數,即String String(attributeValue) , Number(attributeValue) Number ,等等。
Boolean具有特殊的處理,以遵循Web平台的模式。
根據HTML標準:
元素上布爾屬性的存在代表真實值,而屬性的不存在代表假值。
如果存在屬性,則其值必須是空的字符串或值是ASCII案例不敏感的屬性匹配的屬性屬性名稱,而沒有領先或尾隨的空格。
Array和Object用於屬性,沒有特殊的處理,因此使用其構造函數作為其他任何值類型進行轉換,除了布爾。
this將傳遞給您的(),這更乾淨。特別是在破壞時。但是,您仍然可以手動參考它們。
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 ( ) ) ; 當properties()中的任何屬性都會更改時, lit-element將自動重新渲染。通過attrName映射到屬性的屬性也是如此。
如果您需要手動重新渲染,則可以通過調用invalidate()觸發重新渲染。這將安排一個微型掩體,該微型掩飾將在下一個requestAnimationFrame之前渲染內容。
自定義元素在工作之前需要升級。當瀏覽器擁有所需的所有資源時,這會自動發生。
這意味著,如果您執行取決於其他自定義元素並將屬性用於數據流的自定義元素,則在升級該元素之前設置這些屬性,這意味著您最終會遮蓋lit-html-element屬性,這意味著屬性更新和屬性反射無法正常工作。
當允許等待所有依賴項升級時,有一個API whenAllDefined(result, container) 。使用它的一種方法是覆蓋renderCallback() :
renderCallback ( ) {
if ( "resolved" in this ) {
super . renderCallback ( ) ;
} else {
whenAllDefined ( this . render ( this ) ) . then ( ( ) => {
this . resolved = true ;
this . renderCallback ( ) ;
} ) ;
}
}但是,如果您在升級之前手動設置值,則可能仍然設法蒙上陰影屬性
document . getElementById ( 'ninja' ) . firstName = "Ninja" ;因此,以下方式守護這些:
customElements . whenDefined ( 'computed-world' ) . then ( ( ) => {
document . getElementById ( 'ninja' ) . firstName = "Ninja" ;
} ) ;如果您需要一些計算的屬性並根據其他屬性進行更新,則可以使用“計算”值,該值將用參數定義為字符串的對象方法。
僅當定義所有因屬性時,才能更新計算屬性。可以使用value:
注意,計算的屬性不能反映到屬性。
例如。
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 > 可以使用Typescript而不是JavaScript使用lit-html-element 。使用TypeScript時,您可以選擇使用裝飾器,而不是定義靜態static get properties() 。
使用屬性裝飾器時,任何此類靜態屬性登錄器都將被忽略,您也無需致電.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 >為了使用TypeScript中的裝飾器,您需要在tsconfig.json中啟用experimentalDecorators編譯器設置或使用--experimentalDecorators用戶標誌。
{
"compilerOptions" : {
"experimentalDecorators" : true
}
}啟用了上述功能,您可以開始使用裝飾器,但必須手動指定類型信息:
@ property ( { type : String } )
myProperty: string ;由於通常可以從屬性派生,尤其是在定義類型的打字稿中,這感覺就像是雙重工作。幸運的是,有一個新的規範提案稱為元數據反射,旨在解決此問題。該提案尚未正式向TC39工作組正式提出(定義JavaScript標準),但是在打字稿中已經有一個可用的多填充和實驗支持。
啟用了元數據反射,可以更簡單地定義屬性類型:
@ property ( ) myProperty: string ;為了使用Typescript的裝飾器,請按照以下步驟進行操作。
tsconfig.json中啟用emitDecoratorMetadata編譯器設置,或使用--emitDecoratorMetadata標誌。 {
"compilerOptions" : {
"emitDecoratorMetadata" : true
}
}$ npm install --save-dev rbuckton/reflect-metadata < script src =" /node_modules/reflect-metadata/Reflect.js " > </ script >以下API文檔使用Web IDL。
PropertyOptions PropertyOptions用於配置自定義元素的屬性。在JavaScript中,您需要實現一個稱為properties的靜態屬性訪問器,該屬性返回一個對象,該對象的每個屬性都具有關聯的PropertyOptions :
class {
static get properties ( ) {
return { selfDefinedObjectProperty : ... }
}
} PropertyOptions詞典具有4個可選屬性,以下以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屬性type屬性僅在使用裝飾器和元數據反射時是可選的。
value屬性value屬性定義了屬性的默認值。如果通過attrName進行屬性 /屬性映射(請參見下文),則忽略了value 。使用裝飾器時,該值是從屬性定義本身中獲取的:
@ property ( ) myProperty: string = "Hello World" ; attrName屬性attrName定義了屬性的名稱,該名稱應用屬性反映出,另一方面應反映。使用attrName ,默認值將被忽略並從自定義元素,即。取決於屬性是否存在。
屬性名稱,很大程度上是拉丁字母(AZ),包括“ - ”(連字符)。 HTML文檔中HTML元素上的所有屬性會自動獲得ASCII-LOWERCALCOLCATION,並且初始連字符(' - ')被忽略。
請注意,數據屬性,即。以data-開頭的屬性可以通過element.dataset自動作為屬性訪問。
當映射的屬性在元素上設置時,屬性將使用新值的字符串表示形式進行更新,除非新值undefined ,在該值中刪除了屬性。
有一個例外,因為布爾的屬性反映了不同。將屬性設置為true ,屬性(SAI attr )設置為“空字符串'' (含義存在屬性,即<div attr> )。將屬性設置為false ,並刪除屬性,即。 <div> 。
設置屬性時,使用其類型構造函數轉換值,即String(attributeValue) , Number(attributeValue)的String , Number ,等等。
Boolean具有特殊的處理,以遵循Web平台的模式。
根據HTML標準:
元素上布爾屬性的存在代表真實值,而屬性的不存在代表假值。
如果存在屬性,則其值必須是空的字符串或值是ASCII案例不敏感的屬性匹配的屬性屬性名稱,而沒有領先或尾隨的空格。
在上面的“屬性反射”部分中閱讀更多內容。
computed屬性可以使用computed的其他屬性來計算屬性,它採用諸如'methodName(property1, property2)'之類的字符串,其中methodName是元素上的方法,而property1和property2定義。
僅當定義所有因屬性時,才能更新計算屬性。可以使用value:
注意,計算的屬性不能反映到屬性。
renderCallback renderCallback允許在渲染之前和之後進行自定義鉤。
如果您需要在渲染之前進行額外的工作,例如基於另一個屬性設置屬性,則子類可以覆蓋renderCallback()以在基類調用render()之前或之後進行工作,包括在render()之前設置依賴性屬性。
withProperties()托多:
render(HTMLElement this)托多:在這裡移動文檔
async invalidate()托多:在這裡移動文檔
$(DOMString id)托多:在這裡移動文檔
whenAllDefined(TemplateResult result)托多:在這裡移動文檔
@customElement(USVString tagname)用於註冊自定義元素的課堂裝飾器
@ customElement ( 'my-element' )
class extends HTMLElement {
...
}@property(optional PropertyOptions options)用於連接到lit-html-element屬性系統的物業裝飾器。
使用屬性裝飾器時,您不需要定義靜態屬性訪問器static get properties() 。
使用屬性裝飾器時,任何此類靜態屬性登錄器都將被忽略,您也無需致電.withProperties() 。
@ property ( { type : String } )
myProperty: string ;檢查擴展名以獲取打字稿以獲取更多信息。
@attribute(USVString attrName)用於連接到lit-html-element屬性系統並將屬性與自定義元素屬性相關聯的屬性裝飾器。
檢查attrName屬性以獲取更多信息。
@computed(any dependency1, any dependency2, ...)用於連接到lit-html-element屬性系統的屬性裝飾器,並創建自動計算的屬性。
檢查computed屬性以獲取更多信息。
@listen(USVString eventName, (USVString or EventTarget) target)用於添加活動聽眾的方法裝飾器。您可以將字符串用於目標,它將使用該id搜索Shadowroot中的元素。
第一個渲染後,添加了事件偵聽器,從而創建了陰影DOM。