Mixin

类 Mixin 是一种在类之间共享代码的模式,使用标准 JavaScript。与 响应式控制器 这样的“has-a”组合模式(其中一个类可以拥有一个控制器来添加行为)相反,Mixin 实现“is-a”组合,其中 Mixin 导致类本身成为正在共享的行为的实例。

你可以使用 Mixin 通过添加 API 或覆盖其生命周期回调来自定义 Lit 组件。

Mixin 可以被认为是“子类工厂”,它们会覆盖它们应用到的类并返回一个子类,该子类扩展了 Mixin 中的行为。因为 Mixin 是使用标准 JavaScript 类表达式实现的,所以它们可以使用所有可用于子类化的习语,例如添加新字段/方法、覆盖现有超类方法以及使用 super

为了便于阅读,此页面上的示例省略了 Mixin 函数的一些 TypeScript 类型。有关在 TypeScript 中对 Mixin 进行正确类型化的详细信息,请参阅 TypeScript 中的 Mixin

要定义一个 Mixin,请编写一个函数,该函数接受一个 superClass,并返回一个扩展它的新类,并根据需要添加字段和方法

要应用一个 Mixin,只需将一个类传递给它以生成一个应用了 Mixin 的子类。最常见的是,用户在定义新类时会将 Mixin 直接应用于基类

Mixin 也可以用于创建具体的子类,用户可以像普通类一样扩展这些子类,其中 Mixin 是一个实现细节

因为类 Mixin 是一种标准 JavaScript 模式,而不是 Lit 特定的,所以社区中有很多关于利用 Mixin 进行代码重用的信息。有关 Mixin 的更多阅读内容,这里有一些不错的参考资料

  • 类 Mixin 在 MDN 上
  • 使用 JavaScript 类实现真正的 Mixin 由 Justin Fagnani
  • Mixin 在 TypeScript 手册中。
  • 去重 Mixin 库 由 open-wc 提供,包括关于何时 Mixin 的使用会导致重复以及如何使用去重库来避免重复的讨论。
  • Mixin 约定 由 Elix web 组件库遵循。虽然它不是 Lit 特定的,但它包含有关在为 web 组件定义 Mixin 时应用约定的深思熟虑的建议。

应用于 LitElement 的 Mixin 可以实现或覆盖任何标准的 自定义元素生命周期 回调(如 constructor()connectedCallback()),以及任何 响应式更新生命周期 回调(如 render()updated())。

例如,以下 Mixin 将在元素被创建、连接和更新时记录日志

请注意,Mixin 应该始终对 LitElement 实现的标准自定义元素生命周期方法进行超级调用。当覆盖响应式更新生命周期回调时,如果超类中已经存在超方法,那么最好调用超方法(如上面的 super.updated?.() 可选链调用所示)。

还要注意,Mixin 可以选择通过选择何时进行超级调用来在标准生命周期回调的基实现之前或之后执行工作。

Mixin 还可以向子类化的元素添加 响应式属性样式 和 API。

下面的示例中的 Mixin 为元素添加了一个 highlight 响应式属性,以及一个 renderHighlight() 方法,用户可以使用它来包装一些内容。当 highlight 属性/属性被设置时,包装的内容将以黄色显示。

请注意上面的示例中,Mixin 的用户预计会从其 render() 方法中调用 renderHighlight() 方法,并注意将 Mixin 定义的 static styles 添加到子类样式中。这种 Mixin 和用户之间的契约性质取决于 Mixin 的定义,应该由 Mixin 作者记录。

在 TypeScript 中编写 LitElement Mixin 时,需要注意一些细节。

如果存在,你应该将 superClass 参数约束到你期望用户扩展的类类型。这可以通过使用下面所示的泛型 Constructor 帮助程序类型来实现

上面的示例确保传递给 Mixin 的类扩展自 LitElement,这样你的 Mixin 就可以依赖 Lit 提供的回调和其他 API。

尽管 TypeScript 基本支持为使用 Mixin 模式生成的子类推断返回类型,但它有一个严重限制,即推断出的类不能包含具有 privateprotected 访问修饰符的成员。

因为 LitElement 本身确实具有私有和受保护的成员,所以默认情况下,TypeScript 将在返回扩展 LitElement 的类时出错,并显示“导出类表达式的属性 '...' 不能是私有或受保护的。”

有两种解决方法,它们都涉及将 Mixin 函数的返回类型强制转换为类型,以避免上述错误。

当 Mixin 不添加新的公共/受保护 API 时

“当 Mixin 不添加新的公共/受保护 API 时”的永久链接

如果你的 Mixin 只覆盖 LitElement 方法或属性,并且不添加任何自己的新 API,则可以简单地将生成的类强制转换为传递的超类类型 T

当 Mixin 添加新的公共/受保护 API 时

“当 Mixin 添加新的公共/受保护 API 时”的永久链接

如果你的 Mixin 添加了新的受保护或公共 API,你需要用户能够在他们的类上使用这些 API,则需要分别定义 Mixin 的接口,并将其返回类型强制转换为 Mixin 接口和超类类型的交集

由于 TypeScript 类型系统的限制,装饰器(如 @property())必须应用于类声明语句,而不是类表达式。

在实践中,这意味着 TypeScript 中的 Mixin 需要声明一个类,然后返回它,而不是直接从箭头函数中返回类表达式。

支持

不支持