为什么需要 LitElement

Permalink to "为什么需要 LitElement"

代码仍然有改进的空间:

  1. 如果 vote 属性或 attribute 被更改,rating 属性可能也会被更改,这会导致 render 被调用两次。尽管重复调用 render非常高效的,但浏览器仍然不必要地调用了该函数两次。
  2. 添加新属性和 attribute 非常繁琐,因为需要大量样板代码。

这就是 LitElement 发挥作用的地方!

LitElement 是 Lit 用于创建快速、轻量级 Web Components 的基类,可在不同框架和环境中使用。接下来,看看 LitElement 能为 <rating-element> 做些什么!

定义一个 LitElement

Permalink to "定义一个 LitElement"

首先从 lit 包中导入并继承 LitElement 基类 , 并使用 @customElement 装饰器来替代 customElements.define 调用。

rating-element.

Permalink to "rating-element."
import {LitElement, html, css} from 'lit';
import {customElement} from 'lit/decorators.js';

// 记住要继承 LitElement
@customElement('rating-element')
export class RatingElement extends LitElement {
// 移除 connectedCallback()
// 移除文件末尾的 customElements.define
// 注释掉 observedAttributes 方法。这会暂时
// 破坏功能,但会在下一步中解决
...
import {LitElement, html, css} from 'lit';

// 记住要继承 LitElement
export class RatingElement extends LitElement {
// 移除 connectedCallback()
// 暂时注释掉 observedAttributes 方法,这会
// 暂时破坏功能,但我们会在下一步中解决
...

有哪些变化?

css 标签函数允许你定义 CSS 标签模板字面量,它在底层支持数学运算、模板等功能。

有关样式的完整功能列表,请参阅 Lit 样式文档

使用 Lit 设置样式

Permalink to "使用 Lit 设置样式"

接下来,将样式从 render 方法移到 Lit 的静态样式表中:

rating-element.

Permalink to "rating-element."
export class RatingElement extends LitElement {
static styles = css`
: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;
}
`;
...
// 从 render 方法中移除 <style>
export class RatingElement extends LitElement {
static styles = css`
: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;
}
`;
...
// 从 render 方法中移除 <style>

这是 Lit 中样式的主要存放位置。

在可用的情况下,Lit 会使用浏览器功能,例如可构造样式表,为你的样式提供更快的渲染速度。

渲染

Permalink to "渲染"

接下来,render()LitElement 的生命周期方法,要求我们返回一个 Lit 模板,并且不再需要检查 shadow root:

rating-element.

Permalink to "rating-element."
render() {
return html`
<button
class="thumb_down"
@click=${() => {this.vote = '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"
@click=${() => {this.vote = '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() {
return html`
<button
class="thumb_down"
@click=${() => {
this.vote = '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"
@click=${() => {
this.vote = '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>`;
}

现在你有了一个带样式的元素!在下一步中,你将使元素响应属性和 attribute 的变化。