苗条的动态html元素未应用CSS

时间:2020-01-09 17:47:47

标签: svelte

我有一个苗条的组件,它使用一个库来显示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>

1 个答案:

答案 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选择器”。

如果将样式设置为全局样式,则编译器不再需要限制它们的范围,因此问题得以解决。