Svelte 动态 html 元素未应用 css
Svelte dynamic html elements do not have css applied
我有一个使用库显示 JSON 树的 svelte 组件,但该库需要一个 html 挂钩才能加载。之后它会生成自己的 html 结构以及自己的 classes 和 id。到目前为止一切顺利,但如果我在我的组件中为将来生成的选择器添加一些样式,则不会应用该样式。
这是问题所在吗?有一些解决办法吗?
这是我的代码示例:
<script>
import { onMount } from "svelte";
import { Content } from "@smui/card";
import { copyToClipboard } from "../../public/js/utils";
export let data;
let contentBody;
onMount(() => {
const editor = new JSONEditor(
contentBody,
{ mode: "view", navigationBar: false },
data
);
const editorMenu = document.getElementsByClassName("jsoneditor-menu")[0];
const copy = document.createElement("img");
copy.src = "../../public/img/copy.png";
copy.setAttribute("class", "custom-button");
editorMenu.append(copy);
copy.onclick = () => copyToClipboard(editor.getText()));
});
</script>
<style>
.jsoneditor-menu {
background-color: #525b69;
border: 1px solid #e8e8e8;
}
.jsoneditor {
border: 1px solid #e8e8e8;
}
.json {
height: 555px;
}
.custom-button {
width: 20px;
height: 20px;
margin: 2px;
padding: 2px;
border-radius: 2px;
border: 1px solid transparent;
color: #fff;
opacity: 0.8;
font-family: arial, sans-serif;
font-size: 10pt;
float: left;
}
</style>
<Content>
<div class="json" bind:this={contentBody} />
</Content>
注意:该样式仅适用于根元素 json
class
是的,您已正确识别问题。解决方案是使用 :global
魔术伪选择器 (docs) 使您的样式全局化。
<style>
/* this will not be removed, and not scoped to the component */
:global(.foo) { ... }
/* this will not be removed, but still scoped to divs inside _this_ component */
div :global(.bar) { ... }
</style>
Svelte 中的 CSS 范围是通过在您编写的 CSS 选择器中添加一个唯一的 class 来实现的。比如你写.foo
,编译器会把它变成.svelte-a3bmb2.foo
.
为此,编译器还需要将此 class 添加到与选择器 .foo
匹配的所有元素。它可以针对它在标记中看到的元素执行此操作。但是对于运行时动态创建的元素就不行了。
这就是为什么(我猜)Svelte 会删除 CSS 与组件标记中的任何内容都不匹配的规则。编译器通常会在执行此操作时发出警告,例如 "unused CSS selector".
如果您将样式设置为全局样式,编译器就不再需要限定它们的范围,所以问题就解决了。
我有一个使用库显示 JSON 树的 svelte 组件,但该库需要一个 html 挂钩才能加载。之后它会生成自己的 html 结构以及自己的 classes 和 id。到目前为止一切顺利,但如果我在我的组件中为将来生成的选择器添加一些样式,则不会应用该样式。
这是问题所在吗?有一些解决办法吗?
这是我的代码示例:
<script>
import { onMount } from "svelte";
import { Content } from "@smui/card";
import { copyToClipboard } from "../../public/js/utils";
export let data;
let contentBody;
onMount(() => {
const editor = new JSONEditor(
contentBody,
{ mode: "view", navigationBar: false },
data
);
const editorMenu = document.getElementsByClassName("jsoneditor-menu")[0];
const copy = document.createElement("img");
copy.src = "../../public/img/copy.png";
copy.setAttribute("class", "custom-button");
editorMenu.append(copy);
copy.onclick = () => copyToClipboard(editor.getText()));
});
</script>
<style>
.jsoneditor-menu {
background-color: #525b69;
border: 1px solid #e8e8e8;
}
.jsoneditor {
border: 1px solid #e8e8e8;
}
.json {
height: 555px;
}
.custom-button {
width: 20px;
height: 20px;
margin: 2px;
padding: 2px;
border-radius: 2px;
border: 1px solid transparent;
color: #fff;
opacity: 0.8;
font-family: arial, sans-serif;
font-size: 10pt;
float: left;
}
</style>
<Content>
<div class="json" bind:this={contentBody} />
</Content>
注意:该样式仅适用于根元素 json
class
是的,您已正确识别问题。解决方案是使用 :global
魔术伪选择器 (docs) 使您的样式全局化。
<style>
/* this will not be removed, and not scoped to the component */
:global(.foo) { ... }
/* this will not be removed, but still scoped to divs inside _this_ component */
div :global(.bar) { ... }
</style>
Svelte 中的 CSS 范围是通过在您编写的 CSS 选择器中添加一个唯一的 class 来实现的。比如你写.foo
,编译器会把它变成.svelte-a3bmb2.foo
.
为此,编译器还需要将此 class 添加到与选择器 .foo
匹配的所有元素。它可以针对它在标记中看到的元素执行此操作。但是对于运行时动态创建的元素就不行了。
这就是为什么(我猜)Svelte 会删除 CSS 与组件标记中的任何内容都不匹配的规则。编译器通常会在执行此操作时发出警告,例如 "unused CSS selector".
如果您将样式设置为全局样式,编译器就不再需要限定它们的范围,所以问题就解决了。