我有一个苗条的组件,它使用一个库来显示JSON树,但是该库需要一个html钩子将其加载到哪里。然后,它使用自己的类和ID生成自己的html结构。到目前为止,一切都很好,但是如果我在组件内部添加一些将来生成的选择器样式,则不会应用该样式。
这是问题吗?有什么解决方法吗?
这是我的代码示例:
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis.MSBuild;
// I use this so I don't get confused with the Roslyn Project type
using MSBuildProject = Microsoft.Build.Evaluation.Project;
namespace loadProject {
class Program {
static async Task Main(string[] args) {
MSBuildWorkspaceSetup();
// NOTE: we need to make sure we call MSBuildLocator.RegisterInstance
// before we ask the CLR to load any MSBuild types. Therefore we moved
// the code that uses MSBuild types to its own method (instead of being in
// Main) so the CLR is not forced to load them on startup.
await DoAnalysisAsync(args[0]);
}
private static async Task DoAnalysisAsync(string solutionPath) {
using var workspace = MSBuildWorkspace.Create();
// Print message for WorkspaceFailed event to help diagnosing project load failures.
workspace.WorkspaceFailed += (o, e) => Console.WriteLine(e.Diagnostic.Message);
Console.WriteLine($"Loading solution '{solutionPath}'");
// Attach progress reporter so we print projects as they are loaded.
var solution = await workspace.OpenSolutionAsync(solutionPath, new ConsoleProgressReporter());
Console.WriteLine($"Finished loading solution '{solutionPath}'");
// We just select the first project as a demo
// you will want to use your own logic here
var project = solution.Projects.First();
// Now we use the MSBuild apis to load and evaluate our project file
using var xmlReader = XmlReader.Create(File.OpenRead(project.FilePath));
ProjectRootElement root = ProjectRootElement.Create(xmlReader, new ProjectCollection(), preserveFormatting: true);
MSBuildProject msbuildProject = new MSBuildProject(root);
// We can now ask any question about the properties or items in our project file
// and get the correct answer
string spaRootValue = msbuildProject.GetPropertyValue("SpaRoot");
}
private static void MSBuildWorkspaceSetup() {
// Attempt to set the version of MSBuild.
var visualStudioInstances = MSBuildLocator.QueryVisualStudioInstances().ToArray();
var instance = visualStudioInstances.Length == 1
// If there is only one instance of MSBuild on this machine, set that as the one to use.
? visualStudioInstances[0]
// Handle selecting the version of MSBuild you want to use.
: SelectVisualStudioInstance(visualStudioInstances);
Console.WriteLine($"Using MSBuild at '{instance.MSBuildPath}' to load projects.");
// NOTE: Be sure to register an instance with the MSBuildLocator
// before calling MSBuildWorkspace.Create()
// otherwise, MSBuildWorkspace won't MEF compose.
MSBuildLocator.RegisterInstance(instance);
}
private static VisualStudioInstance SelectVisualStudioInstance(VisualStudioInstance[] visualStudioInstances) {
Console.WriteLine("Multiple installs of MSBuild detected please select one:");
for (int i = 0; i < visualStudioInstances.Length; i++) {
Console.WriteLine($"Instance {i + 1}");
Console.WriteLine($" Name: {visualStudioInstances[i].Name}");
Console.WriteLine($" Version: {visualStudioInstances[i].Version}");
Console.WriteLine($" MSBuild Path: {visualStudioInstances[i].MSBuildPath}");
}
while (true) {
var userResponse = Console.ReadLine();
if (int.TryParse(userResponse, out int instanceNumber) &&
instanceNumber > 0 &&
instanceNumber <= visualStudioInstances.Length) {
return visualStudioInstances[instanceNumber - 1];
}
Console.WriteLine("Input not accepted, try again.");
}
}
private class ConsoleProgressReporter : IProgress<ProjectLoadProgress> {
public void Report(ProjectLoadProgress loadProgress) {
var projectDisplay = Path.GetFileName(loadProgress.FilePath);
if (loadProgress.TargetFramework != null) {
projectDisplay += $" ({loadProgress.TargetFramework})";
}
Console.WriteLine($"{loadProgress.Operation,-15} {loadProgress.ElapsedTime,-15:m\\:ss\\.fffffff} {projectDisplay}");
}
}
}
}
注意:该样式仅适用于根元素<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>
类
答案 0 :(得分:4)
是的,您已经正确识别了问题。解决方案是使用: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选择器时添加一个唯一的类来实现的。例如,如果您编写.foo
,则编译器会将其转换为.svelte-a3bmb2.foo
。
为此,编译器还需要将该类添加到与选择器.foo
匹配的所有元素中。它可以为在标记中看到的元素做到这一点。但是对于在运行时动态创建的元素,它不能做到这一点。
这就是为什么(我猜)Svelte删除了与组件标记中的任何内容都不匹配的CSS规则。通常,编译器在执行此操作时会发出警告,例如“未使用的CSS选择器”。
如果将样式设置为全局样式,则编译器不再需要限制它们的范围,因此问题得以解决。