typescript 是否可以基于外部属性覆盖Lit组件中的静态样式?

ryoqjall  于 2023-03-24  发布在  TypeScript
关注(0)|答案(1)|浏览(71)

我尝试将主题指定为属性,然后覆盖Lit元素上的static styles属性。
这将是方便的,因为这样我就可以与我的用户共享一个界面,这样他们就可以用一种类型安全的方式为他们自己的应用程序编写我的Web组件的自定义主题。
然而,当我改变static styles属性时,Lit似乎没有意识到这个变化,实际上什么也没有发生。我已经尝试在constructorconnectedCallback方法中这样做了,但都没有成功。在我的真实用例中,它稍微复杂一些,因为我有一个BaseComponent被其他组件继承了它的样式,但让我们把它放在一边来讨论这个问题。我想是吧
这真的可能吗?或者我应该坚持使用styleMapclassMap和常规的CSS自定义属性。
在Lit的Discord服务器上,另一个用户提到我可能需要使用Constructable Stylesheets--这显然是Lit在幕后使用的--但我不确定从哪里开始。
你可以看看这个例子在利特的操场在这里。
我认为部分问题在于我似乎无法在运行时更改组件(static styles)的样式表部分,只能在编译(转译)时更改。
照明组件:

import {html, css, unsafeCSS, LitElement} from 'lit';
import {customElement, property} from 'lit/decorators.js';

type Color = string;
interface CustomTheme {
  primary: Color;
}

const customTheme = {
  primary: "orange"
}
    
function themeToLitCss(theme: CustomTheme) {
  return css`
    p {
      color: ${unsafeCSS(theme.primary)}
    }
  `
}

@customElement('hello-world')
export class HelloWorld extends LitElement {
  static styles = [];

  @property({
  attribute: 'custom-theme',
  converter: (attrValue: string | undefined) =>
    attrValue ? JSON.parse(attrValue) : undefined,
  })
  customTheme?: CustomTheme;
  
  override connectedCallback() {
    super.connectedCallback();
    
    // Overriding the styles with an external theme specified by the user
    if (this.customTheme) HelloWorld.styles = [this.customTheme];
  }

  render() {
    return html`<p>Hello World</p>`;
  }
}

HTML看起来像这样:

<hello-world custom-theme='{"primary": "orange"}'></hello-world>

我还在Lit的Github repo上创建了an issue

clj7thdc

clj7thdc1#

我在Github上有一个discussion with @justinfagnani,后来我根据他的评论想出了这个解决方案。
下面是它的改编示例:

import {html, css, unsafeCSS, LitElement} from 'lit';
import {customElement, property} from 'lit/decorators.js';

type Color = string;
interface CustomTheme {
  primary: Color;
}
    
function themeToLitCss(theme: CustomTheme) {
  return css`
     p {
       color: ${unsafeCSS(theme.primary)}
     }
  `
}

@customElement('hello-world')
export class HelloWorld extends LitElement {
  @property({
  attribute: 'custom-theme',
  converter: (attrValue: string | undefined) =>
    attrValue ? JSON.parse(attrValue) : undefined,
  })
  customTheme?: CustomTheme;

  render() {
    return html`
      <style>
        ${themeToLitCss(this.customTheme)}
      </style>
        
      <p>Hello World</p>
    `;
  }
}

它实际上是基于每个示例工作的:

<hello-world custom-theme='{"primary": "orange"}'></hello-world>
<hello-world custom-theme='{"primary": "red"}'></hello-world>

这里是链接到它在点燃的Playground。
我仍然相信一个更加框架原生的方法会使它更干净,但现在就这样做。

相关问题