我正在使用 Lit 渲染一个嵌套列表。如果我将列表元素推送到一个数组中,并将子列表推送为完整的 Lithtml
模板对象,那么一切正常,我就可以用模板渲染嵌套列表了html`<ul>${myArray}</ul>`
。
但是,如果我将子列表作为它们各自的部分(<ul>
,,<li>Sub-First
...,</ul>
)推送,那么 UL 元素似乎会按无序方式呈现<ul></ul><li>Sub-First
。
完整的工作示例(假设您已经下载了 Lit 代码的副本lit-all.min.js
):
渲染列表.html
<!DOCTYPE html>
<html>
<head>
<script type="module" src="render-list.js"></script>
</head>
<body>
<render-list type="1"></render-list>
<render-list type="2"></render-list>
</body>
</html>
渲染列表.js
import {LitElement, html} from "./lit-all.min.js";
export class RenderList extends LitElement {
static properties = {
type: {type: Number}
};
constructor() {
super();
this.type = 0;
}
render() {
if (this.type == 1) {
let lst = [];
lst.push(html`<li>One`);
lst.push(html`<li>Two`);
let sublst = [];
sublst.push(html`<li>Sublist One`);
sublst.push(html`<li>Sublist Two`);
lst.push(html`<ul>${sublst}</ul>`);
lst.push(html`<li>Three`);
return html`
<h1>This list rendering works</h1>
<ul>${lst}</ul>
`;
}
else {
let lst = [];
lst.push(html`<li>One`);
lst.push(html`<li>Two`);
lst.push(html`<ul>`);
lst.push(html`<li>Sublist One`);
lst.push(html`<li>Sublist Two`);
lst.push(html`</ul>`);
lst.push(html`<li>Three`);
return html`
<h1>This list rendering doesn't work</h1>
<ul>${lst}</ul>
`;
}
}
}
customElements.define("render-list", RenderList);
呈现如下:
查看开发人员工具显示第二个列表呈现为:
<ul>
<li>One
<li>Two
<ul></ul>
<li>Sublist One
<li>Sublist Two
<li>Three
<ul>
显然我不太理解 Lit 使用模板的方式。为什么第二种解决方案不起作用?
第二种方法行不通的原因是 Lit 会单独处理每个模板。当您同时推送不包含其内容和结束标签的“ul”时,Lit 会立即将其视为一个完整(空)元素并将其关闭。它不会等待您稍后推送“li”元素和“ul”来完成它。换句话说,Lit 要求您推送的每个模板都必须构成有效的 HTML 片段。它不会将单独的部分模板组装成完整的 DOM 结构。在您的第一种(有效)情况下,您正确地将完整的“ul”...“/ul”作为一个模板推送:
这样,Lit 就能识别层级结构并正确渲染。在第二种(错误)情况下,你需要单独推送开始标签:
导致它在运行时在开始标记后立即关闭。
您可以通过将嵌套列表分组到单个模板中来解决此问题。
或者更好的是,使用数据驱动的方法,在渲染函数中映射数据并正确生成“li”和嵌套的“ul”元素。
Lit 将模板实例渲染到 DOM 中,而不是原始文本。Lit 无法“猜测”您是想将它们分组到单个
<ul>
块中,而是将它们并排注入到父元素中。这就是为什么它们被构建为兄弟元素而不是嵌套元素的原因。当你告诉它:
您基本上是告诉它创建
ul
一个独立的组件,然后li
创建一个另一个独立的组件,然后</ul>
它将不起作用,因为结束标签不能用作独立的标签。相反,只要有层次结构,就在一个 html 块内创建完整的结构。
尝试这样的事情:
这将有助于将
<ul>
和<li>
构建为一个组件。这是 Lit 的备忘单