你是从第 1 步跳过来的吗?

总结一下,我们构建了一个 Web Component,它可以:


为什么需要 Lit 模板?

Permalink to "为什么需要 Lit 模板?"

<template> 标签很有用且性能良好,但它没有与组件的逻辑打包在一起,使得在一个文件中分发组件变得困难。

模板元素也倾向于命令式代码。在许多情况下,与声明式编码模式相比,这会导致代码可读性更差。

这就是 Lit 模板发挥作用的地方!Lit 允许你在 JavaScript 中编写模板,然后高效地渲染和重新渲染这些模板,配合数据来创建和更新 DOM。它类似于 JSX 和虚拟 DOM 库,但它在浏览器中原生运行,在许多情况下比虚拟 DOM 更高效。

本教程只使用了 Lit 模板支持的部分功能。

完整内容请参阅 Lit 文档中的模板部分。

使用 Lit 模板

Permalink to "使用 Lit 模板"

将原生 Web Component <rating-element> 迁移为使用 Lit 模板。Lit 使用标签模板字面量——一种接受模板字符串作为参数并带有特殊语法的函数。

Lit 在底层使用 <template> 元素来提供快速渲染,同时提供一些安全清理功能。

首先,通过向 Web Component 添加 render() 方法,将 index.html 中的 <template> 迁移为 Lit 模板:

index.

Permalink to "index."
// 不要忘记从 Lit 导入!
import {render, html} from 'lit';

export class RatingElement extends HTMLElement {
...
render() {
if (!this.shadowRoot) {
return;
}

const template = html`
<style>
:host {
display: inline-flex;
align-items: center;
}
button {
background: transparent;
border: none;
cursor: pointer;
}

:host([vote=up]) .thumb_up {
fill: green;
}

:host([vote=down]) .thumb_down {
fill: red;
}
</style>
<button class="thumb_down">
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"/></svg>
</button>
<span class="rating">${this.rating}</span>
<button class="thumb_up">
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z"/></svg>
</button>`;

render(template, this.shadowRoot);
}
}

你也可以从 index.html 中删除你的 <template>

在这个 render() 方法中,你定义了一个名为 template 的变量,并调用了 html 标签模板字面量函数。还要注意 span 元素内的文本 ${this.rating}。这是一个 Lit 表达式,它取代了命令式地设置 span 的 innerText

此外,你调用了 Lit 的 render() 方法,它会同步地将模板渲染到 shadow root 中。每次调用组件的 render() 方法时,评分值都会被更新。

最终你将完全不需要命令式地调用 render()。现在,在 connectedCallback 中调用 this.render(),并移除与插入模板和设置 .rating span 的 innerText 相关的逻辑:

rating-element.

Permalink to "rating-element."
connectedCallback() {
this.attachShadow({mode: 'open'});
this.render();

this.shadowRoot!
.querySelector('.thumb_up')!
.addEventListener('click', this._boundOnUpClick);
this.shadowRoot!
.querySelector('.thumb_down')!
.addEventListener('click', this._boundOnDownClick);
}
connectedCallback() {
this.attachShadow({mode: 'open'});
this.render();

this.shadowRoot
.querySelector('.thumb_up')
.addEventListener('click', this._boundOnUpClick);
this.shadowRoot
.querySelector('.thumb_down')
.addEventListener('click', this._boundOnDownClick);
}

现在你的所有逻辑和模板都打包在一个地方了!在下一步中,你将通过将命令式代码移到模板中来清理它们。