原文:https://lit-element.polymer-project.org/guide/templates
1、定義一個渲染模板
1.1 基本規則
要用LitElement 組件定義一個模板,必須為你的模板類寫一個render方法:
import { LitElement, html } from 'lit-element';
class MyElement extends LitElement {
render() {
return html`<p>template content</p>`;
}
}
這里 html`...` 中 html 是引用的父類函數,用模板字符串包裹原始的HTML標簽
組件的 render 方法可以返回 lit-html 可以渲染的任何內容。通常,它返回單個 TemplateResult 對象(與 html 標記函數返回的類型相同)。
完整的例子
import { LitElement, html } from 'lit-element';
class MyElement extends LitElement {
// Implement `render` to define a template for your element.
render(){
/**
* Return a lit-html `TemplateResult`.
*
* To create a `TemplateResult`, tag a JavaScript template literal
* with the `html` helper function.
*/
return html`
<div>
<p>A paragraph</p>
</div>
`;
}
}
customElements.define('my-element', MyElement);
1.2 動態更改模板內容
我們可以通過捕獲加載消息作為屬性,並根據事件設置屬性來改變模板:update-properties.js
import { LitElement, html } from 'lit-element';
/**
* Use this pattern instead.
*/
class UpdateProperties extends LitElement {
static get properties(){
return {
message: String
};
}
constructor() {
super();
this.message = 'Loading';
this.addEventListener('stuff-loaded', (e) => { this.message = e.detail } );
this.loadStuff();
}
render() {
return html`
<p>${this.message}</p>
`;
}
loadStuff() {
setInterval(() => {
let loaded = new CustomEvent('stuff-loaded', {
detail: 'Loading complete.'
});
this.dispatchEvent(loaded);
}, 3000);
}
}
customElements.define('update-properties', UpdateProperties);
該例子中為模板元素綁定了一個加載事件,事件函數模擬3秒后改變元素屬性值,從而動態改變模板。這是動態改變模板的方法。
注意:每一個模板類都必須引用 import { html, LitElement } from 'lit-element'; 就算套用了其他模板也是一樣
2、在模板中使用屬性、循環和條件判斷
2.1 屬性
static get properties() { return { myProp: String }; } ... render() { return html`<p>${this.myProp}</p>`; }
通過靜態的 get properties() 函數指定屬性的類型, 構造函數 constructor() 初始化屬性的初始值
2.2 循環
html`<ul> ${this.myArray.map(i => html`<li>${i}</li>`)} </ul>`;
ES6數組的map方法,為每一個數組元素執行括號中的操作
2.3 三目運算符
html` ${this.myBool? html`<p>Render some HTML if myBool is true</p>`: html`<p>Render some other HTML if myBool is false</p>`} `;
完整的例子
import { LitElement, html } from 'lit-element';
class MyElement extends LitElement {
static get properties() {
return {
myString: { type: String },
myArray: { type: Array },
myBool: { type: Boolean }
};
}
constructor() {
super();
this.myString = 'Hello World';
this.myArray = ['an','array','of','test','data'];
this.myBool = true;
}
render() {
return html`
<p>${this.myString}</p>
<ul>
${this.myArray.map(i => html`<li>${i}</li>`)}
</ul>
${this.myBool?
html`<p>Render some HTML if myBool is true</p>`:
html`<p>Render some other HTML if myBool is false</p>`}
`;
}
}
customElements.define('my-element', MyElement);
一個包含了 get properties(), constructor(), render() 方法的模板
3、給模板元素綁定屬性值
您可以插入JavaScript表達式作為HTML文本內容,基本屬性,布爾屬性,元素屬性和事件處理器的占位符。
- Text content:
<p>${...}</p> - Attribute:
<p id="${...}"></p> - Boolean attribute:
?disabled="${...}" - Property:
.value="${...}" - Event handler:
@event="${...}"
3.1 綁定到正文
html`<div>${this.prop1}</div>`
3.2 綁定到基本屬性
html`<div id="${this.prop2}"></div>`
3.3 綁定到布爾類型屬性
html`<input type="text" ?disabled="${this.prop3}">`
3.4 綁定到元素屬性
html`<input type="checkbox" .value="${this.prop4}"/>`
3.5 綁定到事件處理程序
html`<button @click="${this.clickHandler}">pie?</button>`
完整的例子
import { LitElement, html } from 'lit-element';
class MyElement extends LitElement {
static get properties() {
return {
prop1: String,
prop2: String,
prop3: Boolean,
prop4: String
};
}
constructor() {
super();
this.prop1 = 'text binding';
this.prop2 = 'mydiv';
this.prop3 = true;
this.prop4 = 'pie';
}
render() {
return html`
<!-- text binding -->
<div>${this.prop1}</div>
<!-- attribute binding -->
<div id="${this.prop2}">attribute binding</div>
<!-- boolean attribute binding -->
<div>
boolean attribute binding
<input type="text" ?disabled="${this.prop3}"/>
</div>
<!-- property binding -->
<div>
property binding
<input type="text" .value="${this.prop4}"/>
</div>
<!-- event handler binding -->
<div>event handler binding
<button @click="${this.clickHandler}">click</button>
</div>
`;
}
clickHandler(e) {
console.log(e.target);
}
}
customElements.define('my-element', MyElement);
4、使用slot占位符給模板元素渲染子節點
4.1 slot標簽
要實現如下形式的渲染,必須通過slot占位符標簽實現
<my-element> <p>A child</p> </my-element>
默認情況下,如果元素具有陰影樹,則其子元素根本不會渲染。
要渲染子節點,您的模板需要包含一個或多個<slot>元素,這些元素充當子節點的占位符。
例如定義如下形式的模板
render(){ return html` <div> <slot></slot> </div> `; }
就可以在 <slot> 標簽的位置渲染子節點
<my-element> <p>Render me</p> </my-element>
這些子項不會在DOM樹中移動,但會像它們是<slot>的子項一樣呈現。
任意多個子節點可以填充到一個slot:
<my-element> <p>Render me</p> <p>Me too</p> <p>Me three</p> </my-element>
4.2 使用命名的slot
要將子節點分配給特定的 slot ,請確保該子節點的 slot 屬性與該 slot 的 name 屬性匹配:
render(){ return html` <div> <slot name="one"></slot> </div> `; }
<my-element> <p slot="one">Include me in slot "one".</p> </my-element>
命名 slot 僅接受具有匹配 slot 屬性的子節點。
例如:
import { LitElement, html } from 'lit-element';
class MyElement extends LitElement {
render(){
return html`
<div>
<slot name="one"></slot>
<slot name="two"></slot>
</div>
`;
}
}
customElements.define('my-element', MyElement);
one對one,two對two,沒有名字的不會被渲染
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script> <script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script> <script type="module" src="./my-element.js"></script> <title>lit-element code sample</title> </head> <body> <!-- Assign child to a specific slot --> <my-element> <p slot="two">Include me in slot "two".</p> </my-element> <!-- Named slots only accept children with a matching `slot` attribute. Children with a `slot` attribute can only go into a slot with a matching name. --> <my-element> <p slot="one">Include me in slot "one".</p> <p slot="nope">This one will not render at all.</p> <p>No default slot, so this one won't render either.</p> </my-element> </body> </html>
5、多個模板組合成頁面
您可以從其他LitElement模板組成新的LitElement模板。在以下示例中,我們通過導入其他元素並在模板中使用它們來組成新的<my-page>模板:
my-article.js
import { LitElement, html } from 'lit-element';
class MyArticle extends LitElement {
render() {
return html`
<article>article</article>
`;
}
}
customElements.define('my-article', MyArticle);
my-header.js
import { html, LitElement } from 'lit-element';
class MyHeader extends LitElement {
render() {
return html`
${this.headerTemplate}
`;
}
get headerTemplate() {
return html`<header>header</header>`;
}
}
customElements.define('my-header', MyHeader);
my-footer.js
import { LitElement, html } from 'lit-element';
class MyFooter extends LitElement {
render() {
return html`
<footer>footer</footer>
`;
}
}
customElements.define('my-footer', MyFooter);
用以上三個子模版元素組成頁面元素my-page.js
import { LitElement, html } from 'lit-element';
import './my-header.js';
import './my-article.js';
import './my-footer.js';
class MyPage extends LitElement {
render() {
return html`
<my-header></my-header>
<my-article></my-article>
<my-footer></my-footer>
`;
}
}
customElements.define('my-page', MyPage);
然后配一個 模板元素整合文件,例如 mian.js
import './my-page.js';
在頁面 my-page.html中引用這個文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>lit-element code sample</title> <script src="main.js"></script> </head> <body> <my-page></my-page> <script src="webcomponents-loader.js"></script> </body> </html>
此時可能有 index.html, my-page.html兩個頁面, index.js, main.js兩個腳本文件,需要同時打包輸出,修改rollup,config.js文件,以數組形式輸出多個js文件
import resolve from 'rollup-plugin-node-resolve'; import babel from 'rollup-plugin-babel'; export default [{ input: ['src/index.js'], output: { file: 'build/index.js', format: 'es', sourcemap: true }, plugins: [ resolve(), babel() ], },{ input: ['src/main.js'], output: { file: 'build/main.js', format: 'es', sourcemap: true }, plugins: [ resolve(), babel() ] }];
修改package.json中的html打包命令
"scripts": { "copyindex": "cp src/*.html build", "copywc": "cp -r node_modules/@webcomponents/webcomponentsjs/bundles build && cp node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js build", "build": "rm -rf build && mkdir build && npm run copyindex && npm run copywc && rollup -c", "start": "serve build" },
就可以在build下生成兩個html文件及其對應的js文件了,其他同理可得
6、 lit-html
lit-html作為LitElement的核心,可以使用很多它的其他功能
npm i lit-element@^2.0.0
npm i lit-html@^1.0.0
例如:
import { LitElement, html } from 'lit-element';
import { until } from 'lit-html/directives/until.js';
const content = fetch('./content.txt').then(r => r.text());
html`${until(content, html`<span>Loading...</span>`)}`
讀取一個文件內容作為渲染內容
其他詳見文檔:https://lit-html.polymer-project.org/guide/template-reference#built-in-directives
