如何将Lit组件的装饰器升级至2023-05提案并改为类装饰器?
解决方案
升级后的类装饰器实现
import { assertCSS } from 'lit'; import tailwind from './tailwind.css'; // 你的通用样式表 const injectTheme = (...stylesToInject) => (Class) => { // 按优先级合并样式:通用样式 → 组件原有样式 → 传入的额外样式 let mergedStyles = [tailwind]; // 处理组件原本的静态样式 if (Class.styles) { Array.isArray(Class.styles) ? mergedStyles.push(...Class.styles) : mergedStyles.push(Class.styles); } // 添加用户传入的样式 mergedStyles.push(...stylesToInject); // 过滤无效样式并验证格式 mergedStyles = mergedStyles.filter(style => !!style).map(assertCSS); // 覆盖类的静态styles属性 Class.styles = mergedStyles; return Class; };
使用示例
import { LitElement, customElement } from 'lit'; import styles from './styles.css'; // 装饰器顺序:先注入样式,再注册自定义元素 @injectTheme(styles) @customElement('my-element') class MyElement extends LitElement { // 无需手动声明static styles }
关键细节说明
- 装饰器执行顺序:2023-05提案中类装饰器确实在静态字段初始化后执行,但我们直接修改类的
static styles属性即可——Lit组件初始化时会读取该属性,只要在@customElement注册组件前完成样式注入,就能生效。因此必须将@injectTheme放在@customElement前面。 - 样式合并逻辑:完全保留旧装饰器的优先级:通用tailwind样式最先加载,其次是组件自身原有样式,最后是通过装饰器传入的额外样式。
- 新提案适配:2023-05提案的类装饰器以目标类为参数,修改后必须返回该类(或新类),这和旧提案修改字段initializer的逻辑不同,直接操作类本身即可满足需求。
TC39 2023-05装饰器提案核心特性(翻译)
- 装饰器为普通JS函数,分为类装饰器、字段装饰器、方法装饰器等,对应修饰不同类成员
- 类装饰器在类定义完成、所有静态字段初始化后执行,仅接收目标类作为参数
- 类装饰器可直接修改目标类的静态属性、原型方法,也可返回新类替代原类
- 字段装饰器作用于单个类字段,可拦截字段的初始化、访问等过程
内容的提问来源于stack exchange,提问作者Joe Jankowiak
相关产品推荐
相关产品推荐

