是否可以将 tailwind 类嵌入到 Shadow DOM 内隔离的 Svelte 自定义组件中?

问题描述 投票:0回答:1

我正在 Svelte 和 Tailwind 中构建自定义组件(Web 组件)。

我的目标是让这个组件具有独立的样式,但是我在将 Tailwind 样式表包含在我的自定义组件中时遇到了麻烦,因为它在 Shadow DOM 中被隔离。

MyComponent.svelte

<svelte:options
  customElement={{
    tag: "my-component",
  }}
/>

<script>
  import Child from "./Child.svelte";
</script>

<span class="text-blue-500 p-4">
  Foo
  <Child />
</span>

儿童苗条

<span class="p-4 text-red-500">Bar</span>

使用

<my-component></my-component>
时,它是无样式的,因为该组件位于 ShadowDOM 内部,因此无法访问全局 Tailwind 样式表。

有没有办法将我的组件的完整 Tailwind 样式表嵌入到 Shadow DOM 中?

我在使用 svelte 预处理器方面取得了一些成功

svelte.config.js

export default {
  preprocess: [preprocess(), vitePreprocess()],
};

并在我的组件中包含指向我的顺风样式表的链接

<style lang="postcss" src="./../app.css"></style>

但这非常麻烦,因为我需要为 MyComponent.svelte 的每个子组件添加这一行

tailwind-css svelte web-component
1个回答
0
投票

正如其他成员在评论中所说,对此没有明确的答案。 Shadow DOM 的全部目的是从外部环境中封装组件的内部部分。

话虽如此,您可以使用

adoptedStyleSheets
上提供的新
ShadowRoot
属性做一些事情。就像我们使用 JavaScript API 操作 HTML 树一样,我们也有 COM(CSS 对象模型)API,它允许您使用 JavaScript API 操作 CSS。

这些 API 最近添加的是

adoptedStyleSheets
constructed stylesheet
。这个想法很简单:

  • 使用
    CSSStyleSheet
    构造函数动态构造样式表。
  • 将 CSS/样式规则添加到此样式表。
  • 将此样式表附加到一个或多个影子根。
// Step 1: Construct a stylesheet:
const mySheet = new CSSStyleSheet();

// Step 2: Add the stylesheet rules:
// Specifically, add the Tailwind styles and rules
mySheet.replaceSync('h1 { padding: 2rem }');

// Apply the stylesheet to a document:
document.adoptedStyleSheets = [mySheet];

// Apply the stylesheet to a Shadow Root:
const node = document.createElement('my-component');

// Mode can be `closed` or `open`.
// Of course, doing this for `open` mode doesn't make sense.
const shadow = node.attachShadow({ mode: 'closed' });
shadow.adoptedStyleSheets = [mySheet];

为了将其附加到顶级

document
对象,您可以简单地执行以下操作:

// Combine existing sheets with our new one:
document.adoptedStyleSheets = [...document.adoptedStyleSheets, mySheet];

这应该可以解决您的问题,并使全局样式在您想要的所有影子根中可用。 但是现在,问题在哪里?

顺风而行

Tailwind 有两个关键事项需要注意。首先,它不是一个设计系统,您只需获得一个预编译的 CSS 文件即可在项目中引用。没有 CSS 文件。事实上,它更像是一个编译器,在项目编译期间生成 CSS 代码。

其次,它是一个实用性优先的样式框架(注意,样式不是 CSS。它只是碰巧使用与 CSS 相同的语法。)。因此,预计这将在您的 HTML 树、组件中全局可用(如果您使用框架)。现在,它完全违背了 ShadowDOM 的封装理念。

因此,为了使用 Tailwind,首先您必须从编译器/捆绑器(在您的情况下为 Vite.js 或 Svelte)单独生成它。这意味着您可能无法利用框架集成提供的 DX。

麻烦

Tailwind 将生成一个独立的 CSS 文件。如果您使用像 Webpack 这样的捆绑器,那么这很容易。您可能会使用

svelte-loader
raw-loader
将 CSS 作为纯字符串导入,以便您可以创建构造的样式表:

// Ensure that raw-loader or equivalent is configured.
import tailWindCssAsString from '../tailwind.css';

const mySheet = new CSSStyleSheet();
mySheet.replaceSync(tailWindCssAsString);

// ... use the `mySheet` with `adoptedStyleSheets`

或者,如果您不这样做,那么您可能需要使用 CSS

@import
At 规则来指向 CSS,例如:

const mySheet = new CSSStyleSheet();

// Ensure to use correct URL path for loading CSS when app is deployed to the server.
mySheet.replaceSync(`
  @import url("/tailwind.css");
`);

这肯定会增加初始延迟和额外的网络请求,这将导致 FOUC

应用样式表

最后,如果不出意外,您还必须考虑何时何地应用构造的样式表。理想情况下,您希望确保样式应用于组件的所有实例,并且由于您使用的是 Web 组件,因此执行此操作的最佳位置是构造函数,如本文中所示。

由于我之前没有使用过Svelte,所以我不知道它是否提供了构造函数等效的生命周期方法。我想这可能是

onMount
方法,它可以工作,但不如构造函数那么好。

最后一点,您必须对

mode
closed
的每个组件执行此操作。


欲了解更多信息,请阅读thisthat

© www.soinside.com 2019 - 2024. All rights reserved.