<template> 标签很有用且性能良好,但它没有与组件的逻辑打包在一起,使得在一个文件中分发组件变得困难。
模板元素也倾向于命令式代码。在许多情况下,与声明式编码模式相比,这会导致代码可读性更差。
这就是 Lit 模板发挥作用的地方!Lit 允许你在 JavaScript 中编写模板,然后高效地渲染和重新渲染这些模板,配合数据来创建和更新 DOM。它类似于 JSX 和虚拟 DOM 库,但它在浏览器中原生运行,在许多情况下比虚拟 DOM 更高效。
本教程只使用了 Lit 模板支持的部分功能。
完整内容请参阅 Lit 文档中的模板部分。
将原生 Web Component <rating-element> 迁移为使用 Lit 模板。Lit 使用标签模板字面量——一种接受模板字符串作为参数并带有特殊语法的函数。
Lit 在底层使用 <template> 元素来提供快速渲染,同时提供一些安全清理功能。
首先,通过向 Web Component 添加 render() 方法,将 index.html 中的 <template> 迁移为 Lit 模板:
// 不要忘记从 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 相关的逻辑:
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);} 现在你的所有逻辑和模板都打包在一个地方了!在下一步中,你将通过将命令式代码移到模板中来清理它们。