内置指令
指令是函数,可以扩展 Lit,通过定制表达式的渲染方式来实现自定义。Lit 包含一些内置指令,可以帮助满足各种渲染需求。
| 指令 | 摘要 |
|---|---|
样式 | |
根据对象将类列表分配给元素。 | |
根据对象将样式属性列表分配给元素。 | |
循环和条件 | |
| 根据条件渲染两个模板中的一个。 | |
| 根据键值从多个模板中选择并渲染一个。 | |
| 使用函数转换可迭代对象。 | |
| 将可迭代对象中的值渲染到 DOM 中,并可选地进行键控,以实现数据差异化和 DOM 稳定性。 | |
| 将可迭代对象中的值与连接符值交织在一起。 | |
| 创建一个数字序列的可迭代对象,用于在特定次数内进行迭代。 | |
| 如果值已定义,则设置属性;如果未定义,则移除属性。 | |
缓存和变更检测 | |
| 在更改模板时缓存渲染的 DOM,而不是丢弃 DOM。您可以使用此指令在频繁切换大型模板时优化渲染性能。 | |
| 将可渲染值与唯一键关联,如果键更改,则强制 DOM 重新渲染。 | |
| 仅在依赖项之一更改时重新评估模板。 | |
| 如果属性或值与实时 DOM 值不同,则设置属性或值,而不是使用最后渲染的值。 | |
引用渲染的 DOM | |
| 获取模板中渲染的元素的引用。 | |
渲染特殊值 | |
渲染 | |
| 将字符串作为 HTML 而不是文本进行渲染。 | |
| 将字符串作为 SVG 而不是文本进行渲染。 | |
异步渲染 | |
| 渲染占位符内容,直到一个或多个 promise 解析。 | |
将 | |
将 | |
**仅捆绑您使用的内容。** 它们被称为“内置”指令,因为它们是 Lit 包的一部分。但每个指令都是一个独立的模块,因此您的应用程序只捆绑您导入的指令。
您还可以构建自己的指令。有关更多信息,请参见自定义指令.
classMap
“classMap”的永久链接根据对象将类列表分配给元素。
| 导入 | |
| 签名 | |
| 可用位置 |
|
classMap 指令使用 element.classList API,根据用户传递的对象,高效地向元素添加和移除类。对象中的每个键都视为类名,如果与键关联的值为真值,则该类将添加到元素中。在后续的渲染中,任何先前设置的类(假值或不再在对象中)都将被移除。
@customElement('my-element')class MyElement extends LitElement {
@property({type: Boolean}) enabled = false;
render() { const classes = { enabled: this.enabled, hidden: false }; return html`<div class=${classMap(classes)}>Classy text</div>`; }}class MyElement extends LitElement { static properties = { enabled: {type: Boolean}, };
constructor() { super(); this.enabled = false; }
render() { const classes = { enabled: this.enabled, hidden: false }; return html`<div class=${classMap(classes)}>Classy text</div>`; }}customElements.define('my-element', MyElement);classMap 必须是 class 属性中的唯一表达式,但可以与静态值组合在一起。
html`<div class="my-widget ${classMap(dynamicClasses)}">Static and dynamic</div>`;在游乐场中进一步探索 classMap。
styleMap
“styleMap”的永久链接根据对象将样式属性列表分配给元素。
| 导入 | |
| 签名 | |
| 可用位置 |
|
styleMap 指令使用 element.style API,根据用户传递的对象,高效地向元素添加和移除内联样式。对象中的每个键都视为样式属性名称,值视为该属性的值。在后续的渲染中,任何先前设置的样式属性(未定义或 null)都将被移除(设置为 null)。
@customElement('my-element')class MyElement extends LitElement {
@property({type: Boolean}) enabled = false;
render() { const styles = { backgroundColor: this.enabled ? 'blue' : 'gray', color: 'white' }; return html`<p style=${styleMap(styles)}>Hello style!</p>`; }}class MyElement extends LitElement { static properties = { enabled: {type: Boolean}, };
constructor() { super(); this.enabled = false; }
render() { const styles = { backgroundColor: this.enabled ? 'blue' : 'gray', color: 'white' }; return html`<p style=${styleMap(styles)}>Hello style!</p>`; }}customElements.define('my-element', MyElement);对于包含连字符的 CSS 属性,您可以使用驼峰式等效项,或者将属性名称放在引号中。例如,您可以将 CSS 属性 font-family 写成 fontFamily 或 'font-family'。
{ fontFamily: 'roboto' }{ 'font-family': 'roboto' }通过将整个属性名放在引号中,引用 CSS 自定义属性(如 --custom-color)
{ '--custom-color': 'steelblue' }styleMap 必须是 style 属性中的唯一表达式,但可以与静态值组合在一起。
html`<p style="color: white; ${styleMap(moreStyles)}">More styles!</p>`;在游乐场中进一步探索 styleMap。
循环和条件
“循环和条件”的永久链接when
“when”的永久链接根据条件渲染两个模板中的一个。
| 导入 | |
| 签名 | |
| 可用位置 | 任何 |
当 condition 为真时,返回调用 trueCase() 的结果;否则,如果 falseCase 已定义,则返回调用 falseCase() 的结果。
这是一个围绕三元运算符的便利包装器,它使编写内联条件语句(没有 else 语句)更简洁。
class MyElement extends LitElement { render() { return html` ${when(this.user, () => html`User: ${this.user.username}`, () => html`Sign In...`)} `; }}choose
“choose”的永久链接根据将给定的 value 与 case 进行匹配,从 case 列表中选择并评估模板函数。
| 导入 | |
| 签名 | |
| 可用位置 | 任何 |
case 的结构为 [caseValue, func]。value 通过严格相等匹配 caseValue。选择第一个匹配项。case 值可以是任何类型,包括基本类型、对象和符号。
这类似于 switch 语句,但它是表达式,并且没有穿透行为。
class MyElement extends LitElement { render() { return html` ${choose(this.section, [ ['home', () => html`<h1>Home</h1>`], ['about', () => html`<h1>About</h1>`] ], () => html`<h1>Error</h1>`)} `; }}map
“map”的永久链接返回一个可迭代对象,该对象包含对 items 中的每个值调用 f(value) 的结果。
| 导入 | |
| 签名 | |
| 可用位置 | 任何 |
map() 是围绕 for/of 循环 的简单包装器,使在表达式中使用可迭代对象更容易。map() 始终更新就地创建的任何 DOM - 它不执行任何差异化或 DOM 移动。如果您需要,请参见 repeat。map() 比 repeat() 更小更快,因此,如果您不需要差异化和 DOM 稳定性,则优先使用 map()。
class MyElement extends LitElement { render() { return html` <ul> ${map(items, (i) => html`<li>${i}</li>`)} </ul> `; }}repeat
“repeat”的永久链接将可迭代对象中的值渲染到 DOM 中,并可选地进行键控,以实现数据差异化和 DOM 稳定性。
| 导入 | |
| 签名 | |
| 可用位置 | 子表达式 |
重复从可迭代对象生成的系列值(通常为 TemplateResults),并在可迭代对象更改时高效地更新这些项。当提供 keyFn 时,通过在需要时移动生成的 DOM 来维护更新期间的键到 DOM 关联,这通常是使用 repeat 的最有效方式,因为它对插入和删除执行最少的不必要操作。
如果您没有使用键函数,请考虑使用 map().
@customElement('my-element')class MyElement extends LitElement {
@property() items: Array<{id: number, name: string}> = [];
render() { return html` <ul> ${repeat(this.items, (item) => item.id, (item, index) => html` <li>${index}: ${item.name}</li>`)} </ul> `; }}class MyElement extends LitElement { static properties = { items: {}, };
constructor() { super(); this.items = []; }
render() { return html` <ul> ${repeat(this.items, (item) => item.id, (item, index) => html` <li>${index}: ${item.name}</li>`)} </ul> `; }}customElements.define('my-element', MyElement);如果未提供 keyFn,repeat 将执行类似于将项映射到值的简单映射操作,并且 DOM 将针对可能不同的项被重用。
请参见 何时使用 map 或 repeat,以了解何时使用 repeat 和何时使用标准 JavaScript 流程控制。
在游乐场中进一步探索 repeat。
join
“join”的永久链接返回一个可迭代对象,该对象包含 items 中的值,并与 joiner 值交织在一起。
| 导入 | |
| 签名 | |
| 可用位置 | 任何 |
class MyElement extends LitElement {
render() { return html` ${join( map(menuItems, (i) => html`<a href=${i.href}>${i.label}</a>`), html`<span class="separator">|</span>` )} `; }}range
“range”的永久链接返回一个从 start 到 end(不包括 end)的整数可迭代对象,以 step 为增量。
| 导入 | |
| 签名 | |
| 可用位置 | 任何 |
class MyElement extends LitElement {
render() { return html` ${map(range(8), (i) => html`${i + 1}`)} `; }}ifDefined
“ifDefined”的永久链接如果值已定义,则设置属性;如果未定义,则移除属性。
| 导入 | |
| 签名 | |
| 可用位置 | 属性表达式 |
对于 AttributeParts,如果值已定义,则设置属性;如果值未定义(undefined 或 null),则移除属性。对于其他部分类型,此指令无操作。
当单个属性值中存在多个表达式时,如果任何表达式使用 ifDefined 并评估为 undefined/null,则该属性将被移除。这对于设置 URL 属性特别有用,如果 URL 的必需部分未定义,则该属性不应设置,以防止出现 404 错误。
@customElement('my-element')class MyElement extends LitElement {
@property() filename: string | undefined = undefined;
@property() size: string | undefined = undefined;
render() { // src attribute not rendered if either size or filename are undefined return html`<img src="/images/${ifDefined(this.size)}/${ifDefined(this.filename)}">`; }}class MyElement extends LitElement { static properties = { filename: {}, size: {}, };
constructor() { super(); this.filename = undefined; this.size = undefined; }
render() { // src attribute not rendered if either size or filename are undefined return html`<img src="/images/${ifDefined(this.size)}/${ifDefined(this.filename)}">`; }}customElements.define('my-element', MyEleent);在游乐场中进一步探索 ifDefined。
缓存和变更检测
“缓存和变更检测”的永久链接cache
“cache”的永久链接在更改模板时缓存渲染的 DOM,而不是丢弃 DOM。您可以使用此指令在频繁切换大型模板时优化渲染性能。
| 导入 | |
| 签名 | |
| 可用位置 | 子表达式 |
当传递给cache的值在两个或多个TemplateResult之间发生变化时,给定模板的渲染 DOM 节点在未使用时会被缓存。当模板发生变化时,指令会在切换到新值之前缓存当前 DOM 节点,并在切换回先前渲染的值时从缓存中恢复它们,而不是重新创建 DOM 节点。
const detailView = (data) => html`<div>...</div>`;const summaryView = (data) => html`<div>...</div>`;
@customElement('my-element')class MyElement extends LitElement {
@property() data = {showDetails: true, /*...*/ };
render() { return html`${cache(this.data.showDetails ? detailView(this.data) : summaryView(this.data) )}`; }}const detailView = (data) => html`<div>...</div>`;const summaryView = (data) => html`<div>...</div>`;
class MyElement extends LitElement { static properties = { data: {}, };
constructor() { super(); this.data = {showDetails: true, /*...*/ }; }
render() { return html`${cache(this.data.showDetails ? detailView(this.data) : summaryView(this.data) )}`; }}customElements.define('my-element', MyElement);当 Lit 重新渲染模板时,它只更新修改的部分:它不会创建或删除比需要更多的 DOM。但是,当您从一个模板切换到另一个模板时,Lit 会删除旧的 DOM 并渲染一个新的 DOM 树。
cache指令会缓存为给定表达式和输入模板生成的 DOM。在上面的例子中,它会缓存summaryView和detailView模板的 DOM。当您从一个视图切换到另一个视图时,Lit 会替换为新视图的缓存版本并使用最新数据更新它。当这些视图经常被切换时,这可以提高渲染性能。
在游乐场中进一步探索cache。
keyed
“keyed” 的永久链接将可渲染的值与唯一的键关联。当键发生变化时,之前的 DOM 会被移除并丢弃,然后才会渲染下一个值,即使该值(如模板)是相同的。
| 导入 | |
| 签名 | |
| 可用位置 | 任何表达式 |
当您渲染有状态的元素并且需要确保所有元素状态在某些关键数据发生变化时被清除时,keyed非常有用。它本质上是选择退出 Lit 的默认 DOM 重用策略。
如果您需要强制使用新的元素进行“进入”或“退出”动画,那么在某些动画场景中,keyed也非常有用。
@customElement('my-element')class MyElement extends LitElement {
@property() userId: string = '';
render() { return html` <div> ${keyed(this.userId, html`<user-card .userId=${this.userId}></user-card>`)} </div>`; }}class MyElement extends LitElement { static properties = { userId: {}, };
constructor() { super(); this.userId = ''; }
render() { return html` <div> ${keyed(this.userId, html`<user-card .userId=${this.userId}></user-card>`)} </div>`; }}customElements.define('my-element', MyElement);guard
“guard” 的永久链接只有在依赖项之一发生变化时才会重新计算模板,以通过防止不必要的操作来优化渲染性能。
| 导入 | |
| 签名 | |
| 可用位置 | 任何表达式 |
渲染valueFn返回的值,并且只有在依赖项之一的标识发生变化时才会重新计算valueFn。
其中
dependencies是一个用于监视更改的值数组。valueFn是一个返回可渲染值的函数。
guard在不可变数据模式下很有用,因为它可以防止在数据更新之前进行昂贵的操作。
@customElement('my-element')class MyElement extends LitElement {
@property() value: string = '';
render() { return html` <div> ${guard([this.value], () => calculateSHA(this.value))} </div>`; }}class MyElement extends LitElement { static properties = { value: {}, };
constructor() { super(); this.value = ''; }
render() { return html` <div> ${guard([this.value], () => calculateSHA(this.value))} </div>`; }}customElements.define('my-element', MyElement);在这种情况下,只有在value属性发生变化时才会运行昂贵的calculateSHA函数。
在游乐场中进一步探索guard。
live
“live” 的永久链接如果属性或值与实时 DOM 值不同,则设置属性或值,而不是使用最后渲染的值。
| 导入 | |
| 签名 | |
| 可用位置 | 属性或属性表达式 |
在确定是否要更新值时,会将表达式值与实时 DOM 值进行比较,而不是 Lit 的默认行为,即与上次设置的值进行比较。
这对于 DOM 值可能从 Lit 外部发生变化的情况很有用。例如,当使用表达式设置<input>元素的value属性、内容可编辑元素的文本或更改其自身属性或属性的自定义元素时。
在这些情况下,如果 DOM 值发生了变化,但通过 Lit 表达式设置的值没有发生变化,那么 Lit 将不知道要更新 DOM 值,并且会保持不变。如果您不希望这样——如果您希望无论如何都用绑定值覆盖 DOM 值——请使用live()指令。
@customElement('my-element')class MyElement extends LitElement {
@property() data = {value: 'test'};
render() { return html`<input .value=${live(this.data.value)}>`; }}class MyElement extends LitElement { static properties = { data: {}, };
constructor() { super(); this.data = {value: 'test'}; }
render() { return html`<input .value=${live(this.data.value)}>`; }}customElements.define('my-element', MyElement);live()对实时 DOM 值执行严格的相等性检查,如果新值等于实时值,则不执行任何操作。这意味着当表达式会导致类型转换时,不应该使用live()。如果您将live()与属性表达式一起使用,请确保只传递字符串,否则表达式将在每次渲染时更新。
在游乐场中进一步探索live。
渲染特殊值
“渲染特殊值” 的永久链接templateContent
“templateContent” 的永久链接渲染 <template> 元素的内容。
| 导入 | |
| 签名 | |
| 可用位置 | 子表达式 |
Lit 模板是用 Javascript 编码的,这样它们就可以嵌入 Javascript 表达式,使其变得动态。如果您有一个静态 HTML <template>,需要将其包含在您的 Lit 模板中,您可以使用templateContent指令克隆模板内容并将其包含在您的 Lit 模板中。只要模板元素引用在渲染之间没有发生变化,后续渲染将不执行任何操作。
请注意,模板内容应该是由开发人员控制的,并且不能使用不受信任的字符串创建。不受信任的内容的示例包括查询字符串参数和来自用户输入的值。使用此指令渲染的不受信任的模板可能导致跨站点脚本 (XSS)漏洞。
const templateEl = document.querySelector('template#myContent') as HTMLTemplateElement;
@customElement('my-element')class MyElement extends LitElement {
render() { return html` Here's some content from a template element: ${templateContent(templateEl)}`; }}const templateEl = document.querySelector('template#myContent');
class MyElement extends LitElement {
render() { return html` Here's some content from a template element: ${templateContent(templateEl)}`; }}customElements.define('my-element', MyElement);在游乐场中进一步探索templateContent。
unsafeHTML
“unsafeHTML” 的永久链接将字符串作为 HTML 而不是文本进行渲染。
| 导入 | |
| 签名 | |
| 可用位置 | 子表达式 |
Lit 的模板语法的一项关键功能是,只有来自模板字面量的字符串才会被解析为 HTML。由于模板字面量只能在受信任的脚本文件中编写,因此这充当了抵御 XSS 攻击注入不受信任的 HTML 的自然保护措施。但是,在某些情况下,可能需要将未来自脚本文件的 HTML 渲染到 Lit 模板中,例如从数据库中获取的受信任的 HTML 内容。unsafeHTML指令将解析此类字符串作为 HTML,并将其渲染到 Lit 模板中。
请注意,传递给unsafeHTML的字符串必须由开发人员控制,并且不应包含不受信任的内容。不受信任的内容的示例包括查询字符串参数和来自用户输入的值。
使用此指令渲染的不受信任的内容可能会导致跨站点脚本 (XSS)、CSS 注入、数据泄露等漏洞。unsafeHTML使用innerHTML解析 HTML 字符串,因此安全影响与innerHTML相同,如 MDN 文档中所述.
const markup = '<h3>Some HTML to render.</h3>';
@customElement('my-element')class MyElement extends LitElement {
render() { return html` Look out, potentially unsafe HTML ahead: ${unsafeHTML(markup)} `; }}const markup = '<h3>Some HTML to render.</h3>';
class MyElement extends LitElement {
render() { return html` Look out, potentially unsafe HTML ahead: ${unsafeHTML(markup)} `; }}customElements.define('my-element', MyElement);在游乐场中进一步探索unsafeHTML。
unsafeSVG
“unsafeSVG” 的永久链接将字符串作为 SVG 而不是文本进行渲染。
| 导入 | |
| 签名 | |
| 可用位置 | 子表达式 |
与unsafeHTML类似,在某些情况下,可能需要将未来自脚本文件的 SVG 内容渲染到 Lit 模板中,例如从数据库中获取的受信任的 SVG 内容。unsafeSVG指令将解析此类字符串作为 SVG,并将其渲染到 Lit 模板中。
请注意,传递给unsafeSVG的字符串必须由开发人员控制,并且不应包含不受信任的内容。不受信任的内容的示例包括查询字符串参数和来自用户输入的值。使用此指令渲染的不受信任的内容可能会导致跨站点脚本 (XSS)漏洞。
const svg = '<circle cx="50" cy="50" r="40" fill="red" />';
@customElement('my-element')class MyElement extends LitElement {
render() { return html` Look out, potentially unsafe SVG ahead: <svg width="40" height="40" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" version="1.1"> ${unsafeSVG(svg)} </svg> `; }}const svg = '<circle cx="50" cy="50" r="40" fill="red" />';
class MyElement extends LitElement {
render() { return html` Look out, potentially unsafe SVG ahead: <svg width="40" height="40" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" version="1.1"> ${unsafeSVG(svg)} </svg> `; }}customElements.define('my-element', MyElement);在游乐场中进一步探索unsafeSVG。
引用渲染的 DOM
“引用渲染的 DOM” 的永久链接ref
“ref” 的永久链接检索渲染到 DOM 中的元素的引用。
| 导入 | |
| 签名 | |
| 可用位置 | 元素表达式 |
虽然在 Lit 中可以使用模板以声明方式实现大多数 DOM 操作,但高级情况可能需要获取模板中渲染的元素的引用并以命令式方式对其进行操作。这可能有用的一些常见示例包括聚焦表单控件或在容器元素上调用命令式 DOM 操作库。
当放置在模板中的元素上时,ref指令将在渲染后检索该元素的引用。可以通过两种方式之一检索元素引用:传递一个Ref对象或传递一个回调函数。
一个Ref对象充当对元素的引用的容器,可以使用ref模块中找到的createRef帮助方法创建。渲染后,Ref的value属性将设置为该元素,可以在渲染后生命周期(如updated)中访问它。
@customElement('my-element')class MyElement extends LitElement {
inputRef: Ref<HTMLInputElement> = createRef();
render() { // Passing ref directive a Ref object that will hold the element in .value return html`<input ${ref(this.inputRef)}>`; }
firstUpdated() { const input = this.inputRef.value!; input.focus(); }}class MyElement extends LitElement {
inputRef = createRef();
render() { // Passing ref directive a Ref object that will hold the element in .value return html`<input ${ref(this.inputRef)}>`; }
firstUpdated() { const input = this.inputRef.value!; input.focus(); }}customElements.define('my-element', MyElement);也可以将引用回调传递给ref指令。回调将在每次引用元素发生变化时被调用。如果引用回调被渲染到不同的元素位置或在后续渲染中被移除,它将首先用undefined调用,然后用它被渲染到的新元素(如果有)再次调用。请注意,在LitElement中,回调将自动绑定到宿主元素并被调用。
@customElement('my-element')class MyElement extends LitElement {
render() { // Passing ref directive a change callback return html`<input ${ref(this.inputChanged)}>`; }
inputChanged(input?: HTMLInputElement) { input?.focus(); }}class MyElement extends LitElement {
render() { // Passing ref directive a change callback return html`<input ${ref(this.inputChanged)}>`; }
inputChanged(input) { input?.focus(); }}customElements.define('my-element', MyElement);在游乐场中进一步探索ref。
异步渲染
“异步渲染” 的永久链接until
“until” 的永久链接渲染占位符内容,直到一个或多个 promise 解析。
| 导入 | |
| 签名 | |
| 可用位置 | 任何表达式 |
接受一系列值,包括 Promise。值按优先级顺序渲染,第一个参数具有最高优先级,最后一个参数具有最低优先级。如果某个值是 Promise,那么将在它解析之前渲染一个低优先级的值。
值的优先级可用于为异步数据创建占位符内容。例如,具有待处理内容的 Promise 可以作为第一个(最高优先级)参数,非 Promise 加载指示器模板可以作为第二个(低优先级)参数使用。加载指示器会立即渲染,当 Promise 解析时,主要内容会渲染。
@customElement('my-element')class MyElement extends LitElement {
@state() private content = fetch('./content.txt').then(r => r.text());
render() { return html`${until(this.content, html`<span>Loading...</span>`)}`; }}class MyElement extends LitElement { static properties = { content: {state: true}, };
constructor() { super(); this.content = fetch('./content.txt').then(r => r.text()); }
render() { return html`${until(this.content, html`<span>Loading...</span>`)}`; }}customElements.define('my-element', MyElement);在游乐场中进一步探索until。
asyncAppend
“asyncAppend” 的永久链接将 AsyncIterable 中的值按顺序追加到 DOM 中。
| 导入 | |
| 签名 | |
| 可用位置 | 子表达式 |
asyncAppend渲染异步可迭代的值,在之前的值之后追加每个新值。请注意,异步生成器也实现了异步可迭代协议,因此可以被asyncAppend使用。
async function *tossCoins(count: number) { for (let i=0; i<count; i++) { yield Math.random() > 0.5 ? 'Heads' : 'Tails'; await new Promise((r) => setTimeout(r, 1000)); }}
@customElement('my-element')class MyElement extends LitElement {
@state() private tosses = tossCoins(10);
render() { return html` <ul>${asyncAppend(this.tosses, (v: string) => html`<li>${v}</li>`)}</ul>`; }}async function *tossCoins(count) { for (let i=0; i<count; i++) { yield Math.random() > 0.5 ? 'Heads' : 'Tails'; await new Promise((r) => setTimeout(r, 1000)); }}
class MyElement extends LitElement { static properties = { tosses: {state: true}, };
constructor() { super(); this.tosses = tossCoins(10); }
render() { return html` <ul>${asyncAppend(this.tosses, (v) => html`<li>${v}</li>`)}</ul>`; }}customElements.define('my-element', MyElement);在游乐场中进一步探索asyncAppend。
asyncReplace
“asyncReplace” 的永久链接将 AsyncIterable 中的最新值渲染到 DOM 中,并将该值按顺序追加到 DOM 中。
| 导入 | |
| 签名 | |
| 可用位置 | 任何表达式 |
与asyncAppend类似,asyncReplace渲染异步可迭代的值,用每个新值替换之前的值。
async function *countDown(count: number) { while (count > 0) { yield count--; await new Promise((r) => setTimeout(r, 1000)); }}
@customElement('my-element')class MyElement extends LitElement {
@state() private timer = countDown(10);
render() { return html`Timer: <span>${asyncReplace(this.timer)}</span>.`; }}async function *countDown(count) { while (count > 0) { yield count--; await new Promise((r) => setTimeout(r, 1000)); }}
class MyElement extends LitElement { static properties = { timer: {state: true}, };
constructor() { super(); this.timer = countDown(10); }
render() { return html`Timer: <span>${asyncReplace(this.timer)}</span>.`; }}customElements.define('my-element', MyElement);在游乐场中进一步探索asyncReplace。