内置指令

指令是可以通过自定义表达式渲染方式来扩展 Lit 的函数。 Lit 包含了许多内置指令,用于满足各种渲染需求:

指令概述

样式

classMap

基于对象为元素分配一系列类。

styleMap

基于对象为元素设置一系列样式属性。

循环和条件判断

when

根据条件渲染两个模板中的一个。

choose

根据键值从多个模板中渲染一个。

map

使用函数转换可迭代对象。

repeat

将可迭代对象中的值渲染到 DOM 中,可选择使用键来实现数据比较和 DOM 稳定性。

join

用连接值交错可迭代对象的值。

range

创建一个序列中的数字可迭代对象,用于迭代特定次数。

ifDefined

当值已定义时设置属性,值未定义时移除属性。

缓存和变化检测

cache

在更改模板时缓存已渲染的 DOM,而不是丢弃 DOM。

keyed

将可渲染值与唯一键关联,在键更改时强制 DOM 重新渲染。

guard

仅在其依赖项之一发生变化时重新评估模板。

live

当值与实时 DOM 值不同而非最后渲染值不同时设置属性或特性。

引用已渲染的 DOM

ref

获取模板中渲染的元素的引用。

渲染特殊值

templateContent

渲染 <template> 元素的内容。

unsafeHTML

将字符串渲染为 HTML 而非文本。

unsafeSVG

将字符串渲染为 SVG 而非文本。

异步渲染

until

在一个或多个 Promise 解决前渲染占位内容。

asyncAppend

AsyncIterable 产生值时将其附加到 DOM 中。

asyncReplace

AsyncIterable 产生值时将最新值渲染到 DOM 中。

只包含你使用的内容。 这些被称为"内置"指令是因为它们是 Lit 包的一部分。但每个指令都是一个独立的模块,因此你的应用只会包含你导入的指令。

你还可以构建自己的指令。有关更多信息,请参阅自定义指令

基于对象为元素设置一系列类。

导入
签名
可用位置

class 属性表达式(必须是 class 属性中唯一的表达式)

classMap 指令使用 element.classList API 根据用户传递的对象高效地向元素添加和 移除类。对象中的每个键被视为一个类名,如果与该键关联的值为真值,则该类会被添加到元素上。在后续渲染中,任何 先前设置的为假值或不再在对象中的类都会被移除。

classMap 必须是 class 属性中唯一的表达式,但它可以 与静态值组合使用:

playground中进一步探索 classMap

基于对象为元素设置一系列样式属性。

导入
签名
可用位置

style 属性表达式(必须是 style 属性中唯一的表达式)

styleMap 指令使用 element.style API 根据用户传递的对象高效地添加和 移除元素的内联样式。对象中的每个键被视为样式属性名称,值被视为该属性的值。在后续渲染中,任何先前设置但现在为 undefined 或 null 的样式属性都会被移除(设置为 null)。

对于包含破折号的 CSS 属性,你可以使用驼峰式等效写法,或者将属性名称放在引号中。例如,你可以将 CSS 属性 font-family 写成 fontFamily'font-family'

引用诸如 --custom-color 之类的 CSS 自定义属性时,将整个属性名称放在引号中:

styleMap 必须是 style 属性中唯一的表达式,但它可以 与静态值组合使用:

playground中进一步探索 styleMap

根据条件渲染两个模板中的一个。

导入
签名
可用位置

任何位置

condition 为真时,返回调用 trueCase() 的结果,否则如果定义了 falseCase,返回调用 falseCase() 的结果。

这是三元表达式的便捷包装器,使得在没有 else 的情况下编写内联条件变得更加简洁。

根据给定的 value 匹配情况从一系列案例中选择并评估模板函数。

导入
签名
可用位置

任何位置

案例结构为 [caseValue, func]value 通过严格相等与 caseValue 匹配。选择第一个匹配项。案例值可以是任何类型,包括基本类型、对象和符号。

这类似于 switch 语句,但作为表达式且没有穿透效果。

返回一个可迭代对象,包含对 items 中每个值调用 f(value) 的结果。

导入
签名
可用位置

任何位置

map() 是对 for/of 循环的简单封装,使得在表达式中处理可迭代对象变得更容易一些。map() 始终原地更新创建的任何 DOM —— 它不进行任何差异比较或 DOM 移动。如果你需要这些功能,请参考 repeatmap()repeat() 更小更快,所以如果你不需要差异比较和 DOM 稳定性,优先选择 map()

将可迭代对象中的值渲染到 DOM 中,可选择使用键来启用数据差异比较和 DOM 稳定性。

导入
签名
可用位置

子表达式

重复渲染从可迭代对象生成的一系列值(通常是 TemplateResults),并在可迭代对象变化时高效地更新这些项目。当提供 keyFn 时,通过在需要时移动生成的 DOM 来维护更新之间的键到 DOM 的关联,这通常是使用 repeat 的最有效方式,因为它对插入和删除执行最少的不必要工作。

如果你不使用键函数,你应该考虑使用 map()

如果没有提供 keyFnrepeat 的行为类似于简单地将项目映射到值,并且 DOM 将针对可能不同的项目重用。

查看何时使用 map 或 repeat,了解何时使用 repeat 以及何时使用标准 JavaScript 流程控制的讨论。

playground中进一步探索 repeat

返回一个可迭代对象,其中包含 items 中的值与 joiner 值交错排列。

导入
签名
可用位置

任何位置

返回一个可迭代对象,包含从 startend(不包括)按 step 递增的整数。

导入
签名
可用位置

任何位置

当值已定义时设置属性,值未定义时移除属性。

导入
签名
可用位置

属性表达式

对于 AttributeParts,当值已定义时设置属性,当值未定义(undefinednull)时移除属性。对于其他部分类型,此指令不执行任何操作。

当一个属性值中存在多个表达式时,如果_任何_表达式使用 ifDefined 并且计算结果为 undefined/null,则该属性将被移除。这对于设置 URL 属性特别有用,当所需的 URL 部分未定义时,属性不应设置,以防止出现 404 错误。

playground中进一步探索 ifDefined

在更改模板时缓存已渲染的 DOM,而不是丢弃 DOM。你可以使用此指令优化在大型模板之间频繁切换时的渲染性能。

导入
签名
可用位置

子表达式

当传递给 cache 的值在一个或多个 TemplateResult 之间变化时,未使用的模板的渲染 DOM 节点会被缓存。当模板更改时,该指令会在切换到新值之前缓存_当前_ DOM 节点,并在切换回先前渲染的值时从缓存中恢复它们,而不是重新创建 DOM 节点。

当 Lit 重新渲染模板时,它只更新修改的部分:它不会创建或移除超出必要的 DOM。但当你从一个模板切换到另一个模板时,Lit 会移除旧的 DOM 并渲染一个新的 DOM 树。

cache 指令缓存给定表达式和输入模板生成的 DOM。在上面的示例中,它缓存了 summaryViewdetailView 模板的 DOM。当你从一个视图切换到另一个视图时,Lit 会交换新视图的缓存版本并用最新数据更新它。这可以在频繁切换这些视图时提高渲染性能。

playground中进一步探索 cache

将可渲染值与唯一键关联。当键更改时,即使值(如模板)相同,之前的 DOM 也会在渲染下一个值之前被移除和销毁。

导入
签名
可用位置

任何表达式

当你渲染有状态元素并且需要确保关键数据更改时清除元素的所有状态时,keyed 非常有用。它本质上放弃了 Lit 默认的 DOM 重用策略。

在某些动画场景中,如果你需要为"进入"或"退出"动画强制创建新元素,keyed 也很有用。

只有当其依赖项之一更改时才重新评估模板,以通过防止不必要的工作来优化渲染性能。

导入
签名
可用位置

任何表达式

渲染由 valueFn 返回的值,并且只有当依赖项之一的标识发生变化时,才重新评估 valueFn

其中:

  • dependencies 是要监视变化的值数组。
  • valueFn 是返回可渲染值的函数。

guard 在不可变数据模式中很有用,通过防止昂贵的工作直到数据更新时才执行。

在这种情况下,昂贵的 calculateSHA 函数仅在 value 属性改变时运行。

playground中进一步探索 guard

当值与实时 DOM 值不同而非最后渲染值不同时设置属性或特性。

导入
签名
可用位置

属性或特性表达式

在确定是否更新值时,检查表达式值与_实时_ DOM 值的关系,而不是 Lit 默认的检查最后设置值的行为。

这对于 DOM 值可能从 Lit 外部改变的情况非常有用。例如,当使用表达式设置 <input> 元素的 value 属性、可编辑内容元素的文本或者设置自定义元素的自身属性或特性时。

在这些情况下,如果 DOM 值发生变化,但通过 Lit 表达式设置的值没有变化,Lit 不会知道需要更新 DOM 值并会保持不变。如果这不是你想要的效果——如果你希望不管发生什么都用绑定值覆盖 DOM 值——请使用 live() 指令。

live() 对实时 DOM 值执行严格相等检查,如果新值等于实时值,则不执行任何操作。这意味着 live() 不应在表达式会导致类型转换的情况下使用。如果你在属性表达式中使用 live(),请确保只传入字符串,否则表达式将在每次渲染时更新。

playground中进一步探索 live

渲染 <template> 元素的内容。

导入
签名
可用位置

子表达式

Lit 模板是用 JavaScript 编码的,因此它们可以嵌入使其动态化的 JavaScript 表达式。如果你有一个静态的 HTML <template> 需要包含在 Lit 模板中,你可以使用 templateContent 指令来克隆模板内容并将其包含在你的 Lit 模板中。只要模板元素引用在渲染之间不发生变化, 后续渲染将无操作。

注意,模板内容应由开发者控制,且不得使用不可信的字符串创建。例子包括查询字符串参数和用户输入值。使用此指令渲染的不可信模板可能导致 跨站脚本攻击 (XSS) 漏洞。

playground中进一步探索 templateContent

将字符串渲染为 HTML 而非文本。

导入
签名
可用位置

子表达式

Lit 模板语法的一个关键特性是只有源自模板字面量的字符串才会被解析为 HTML。由于模板字面量只能在受信任的脚本文件中编写,这自然地防止了 XSS 攻击注入不可信的 HTML。然而,可能存在需要在 Lit 模板中渲染不是源自脚本文件的 HTML 的情况,例如从数据库获取的受信任的 HTML 内容。unsafeHTML 指令将这样的字符串解析为 HTML 并在 Lit 模板中渲染它。

注意,传递给 unsafeHTML 的字符串必须由开发者控制,且不包含不可信的内容。例子包括查询字符串参数和用户输入值。

使用此指令渲染的不可信内容可能导致 跨站脚本攻击 (XSS)、CSS 注入、数据泄露等漏洞。unsafeHTML 使用 innerHTML 解析 HTML 字符串,因此安全隐患与 innerHTML 相同,参见 MDN 上的文档

playground中进一步探索 unsafeHTML

将字符串渲染为 SVG 而非文本。

导入
签名
可用位置

子表达式

unsafeHTML 类似,可能有需要在 Lit 模板中渲染不是源自脚本文件的 SVG 内容的情况,例如从数据库获取的受信任的 SVG 内容。unsafeSVG 指令将这样的字符串解析为 SVG 并在 Lit 模板中渲染它。

注意,传递给 unsafeSVG 的字符串必须由开发者控制,且不包含不可信的内容。例子包括查询字符串参数和用户输入值。使用此指令渲染的不可信内容可能导致 跨站脚本攻击 (XSS) 漏洞。

playground中进一步探索 unsafeSVG

获取渲染到 DOM 中的元素的引用。

导入
签名
可用位置

元素表达式

虽然 Lit 中的大多数 DOM 操作可以使用模板以声明式方式实现,但高级情况可能需要获取模板中渲染的元素引用并对其进行命令式操作。这在需要聚焦表单控件或在容器元素上调用命令式 DOM 操作库等常见情况下可能很有用。

当放置在模板中的元素上时,ref 指令将在元素渲染后获取该元素的引用。获取元素引用可以通过两种方式之一:传递一个 Ref 对象或传递一个回调函数。

Ref 对象充当元素引用的容器,可以使用 ref 模块中的 createRef 辅助方法创建。渲染后,Refvalue 属性将设置为元素,可以在 updated 等渲染后生命周期中访问它。

也可以将 ref 回调传递给 ref 指令。每次引用的元素发生变化时,都会调用回调。如果在后续渲染中将 ref 回调渲染到不同的元素位置或移除它,它将首先用 undefined 调用,然后再用它渲染到的新元素(如果有)调用。请注意,在 LitElement 中,回调将自动绑定到宿主元素。

playground中进一步探索 ref

在一个或多个 promise 解决前渲染占位内容。

导入
签名
可用位置

任何表达式

接受一系列值,包括 Promise。值按优先级顺序渲染,第一个参数具有最高优先级,最后一个参数具有最低优先级。如果一个值是 Promise,将渲染较低优先级的值,直到它解决。

值的优先级可用于为异步数据创建占位内容。例如,具有待处理内容的 Promise 可以作为第一个(最高优先级)参数,而非 promise 的加载指示器模板可以作为第二个(较低优先级)参数。加载指示器会立即渲染,而主要内容将在 Promise 解决时渲染。

playground中进一步探索 until

AsyncIterable 产生的值附加到 DOM 中。

导入
签名
可用位置

子表达式

asyncAppend 渲染异步可迭代对象的值,将每个新值附加在前一个值之后。请注意,异步生成器也实现了异步可迭代协议,因此可以被 asyncAppend 消费。

playground中进一步探索 asyncAppend

AsyncIterable 产生的最新值渲染到 DOM 中。

导入
签名
可用位置

任何表达式

类似于 asyncAppendasyncReplace 渲染异步可迭代对象的值,用每个新值替换前一个值。

playground中进一步探索 asyncReplace