模板概述
Lit 模板是使用带有html标签的 JavaScript 模板文字编写的。文字的内容大多是简单的、声明性的 HTML:
html`<h1>Hello ${name}</h1>`
表达式
子表达式
出现在元素的开始和结束标记之间的表达式可以将子节点添加到元素。
html`<p>Hello, ${name}</p>`
模板
由于子位置的表达式可以返回 aTemplateResult您可以嵌套和组合模板:
const nav = html`<nav>...</nav>`;
const page = html`
${nav}
<main>...</main>
`;
html`
${this.user.isloggedIn
? html`Welcome ${this.user.name}`
: html`Please log in`
}
`;
dom节点
任何 DOM 节点都可以传递给子表达式。通常 DOM 节点应该通过使用 指定模板来呈现html,但 DOM 节点可以在需要时像这样直接呈现。该节点在该点附加到 DOM 树,因此从任何当前父节点中删除:
const div = document.createElement('div');
const page = html`
${div}
<p>This is some text</p>
`;
属性表达式
html`<div class=${this.textClass}>Stylish text.</div>`;
由于属性值始终是字符串,因此表达式应该返回一个可以转换为字符串的值。
布尔属性
要设置布尔属性,请使用?属性名称的前缀。如果表达式计算结果为真值,则添加该属性,如果计算结果为假值,则删除该属性:
html`<div ?hidden=${!this.showAdditional}>This text may be hidden.</div>`;
删除属性
对于常见的“布尔属性”,例如disabled,hidden您希望将属性设置为空字符串以获得真实值,否则将其删除,请使用布尔属性。但是,有时您可能需要不同的条件(underfind、null、空字符串)来添加或删除属性。
- underfind、null
html`<img src="/images/${this.imagePath ?? nothing}/${this.imageFile ?? nothing}">`;
nothing
相当于一个关键字,标识未定义或者null
也可以使用ifDefined
指令来代替
html`<img src="/images/${ifDefined(this.imagePath)}/${ifDefined(this.imageFile)}">`
- 空字符串
html`<button aria-label="${this.ariaLabel || nothing}"></button>`
.
语法
.
您可以使用前缀和属性名称在元素上设置 JavaScript 属性:
html`<input .value=${this.itemCount}>`;
如果是常见类型,例如string、number之类的.
可以省略,但是如果是数组或者对象则必须加上.
<demo-test .msg=${{ age: 1, name: "哈哈哈" }}></demo-test>
事件表达式
模板还可以包括声明性事件侦听器。使用前缀@后跟事件名称。该表达式应评估为事件侦听器。这点与vue基本一样
html`<button @click=${this.clickHandler}>Click Me!</button>`;
元素表达式
您还可以添加访问元素实例的表达式,而不是元素上的单个属性或属性:
html`<div ${myDirective()}></div>`
元素表达式仅适用于指令。元素表达式中的任何其他值类型都将被忽略。
可以在元素表达式中使用的一个内置指令是ref指令。它提供了对渲染元素的引用。
html`<button ${ref(this.myRef)}`;
有效的表达式位置
表达式只能出现在您可以在 HTML 中放置属性值和子元素的地方。以下位置都是无效的:
- 出现在标签或属性名位置
<!-- ERROR -->
<${tagName}></${tagName}>
<!-- ERROR -->
<div ${attrName}=true></div>
- 内部
<template>
元素内容,(允许模板元素本身的属性表达式)
<!-- ERROR -->
<template>${content}</template>
<!-- OK -->
<template id="${attrValue}">static content ok</template>
- 内部 HTML 注释。
<!-- will not update: ${value} -->
<style>
使用 ShadyCSS polyfill 时的内部元素
条件
由于 Lit 利用了普通的 Javascript 表达式,您可以使用标准的 Javascript 控制流构造,如条件运算符、函数调用和if或switch语句来呈现条件内容。
JavaScript 条件还允许您组合嵌套的模板表达式,您甚至可以将模板结果存储在变量中以在其他地方使用。
三元运算符
带有条件运算符 的三元表达式?是添加内联条件的好方法:
render() {
return this.userName
? html`Welcome ${this.userName}`
: html`Please log in <button>Login</button>`;
}
if语句
render() {
let message;
if (this.userName) {
message = html`Welcome ${this.userName}`;
} else {
message = html`Please log in <button>Login</button>`;
}
return html`<p class="message">${message}</p>`;
}
缓存模板结果:缓存指令
在大多数情况下,条件模板只需要 JavaScript 条件。但是,如果您在大型、复杂的模板之间切换,您可能希望节省每次切换时重新创建 DOM 的成本。
在这种情况下,您可以使用cache 指令。cache 指令为当前未呈现的模板缓存 DOM。
render() {
return html`${cache(this.userName ?
html`Welcome ${this.userName}`:
html`Please log in <button>Login</button>`)
}`;
}
有条件的不渲染
有时,您可能不想在条件运算符的一个分支中呈现任何内容。这通常是子表达式需要的,有时也需要在属性表达式中。
对于子表达式,值undefined, null、空字符串 ( ‘’) 和 Lit 的nothing sentinel 值都不会渲染节点。
// this.userName 存在则渲染<user-name>,否则不渲染
render() {
return html`<user-name>${this.userName ?? nothing}</user-name>`;
}
//有条件地呈现aria-label属性:
html`<button aria-label="${this.ariaLabel || nothing}"></button>`
列表
这块的内容根react中的语法基本一致
渲染数组
@property()
fruit: Array<string> = ["苹果", "橘子", "香蕉"];
// 渲染组件
protected render() {
return html` <p>水果:${this.fruit}</p> `;
}
使用数组的map函数
@property()
colors: Array<string> = ["red", "blue", "pink"];
// 渲染组件
protected render() {
return html`
<ul>
${this.colors.map(
(color) => html`<li style="color: ${color}">${color}</li>`
)}
</ul>
`;
}
for 循环
render() {
const itemTemplates = [];
for (const i of this.items) {
itemTemplates.push(html`<li>${i}</li>`);
}
return html`
<ul>
${itemTemplates}
</ul>
`;
}
重复指令
在大多数情况下,使用循环或是map构建重复模板的有效方法。但是,如果您想重新排序一个大列表,或者通过添加和删除单个条目来改变它,这种方法可能涉及更新大量 DOM 节点。
此时应该使用repeat指令
简单来说就是如果只是展示可以使用循环或者map,但是涉及添加删除操作时使用repeat指令
repeat(items, keyFunction, itemTemplate)
- items是一个数组或可迭代的。
- keyFunction是一个将单个项目作为参数并返回该项目的保证唯一键的函数。
- itemTemplate是一个模板函数,它将项目及其当前索引作为参数,并返回一个TemplateResult.
import { LitElement, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { repeat } from "lit/directives/repeat.js";
@customElement("base-app")
export class BaseApp extends LitElement {
@property()
person: Array<personItem> = [
{ id: 1, name: "张三" },
{ id: 2, name: "李四" },
{ id: 3, name: "王五" },
];
// 渲染组件
protected render() {
return html`
<ul>
${repeat(
this.person,
(item) => item.id,
(item, index) => html` <li>${index}:${item.name}</li> `
)}
</ul>
`;
}
}
interface personItem {
id: number;
name: string;
}