原文: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