Svelte 中 class 的条件样式

Conditional styling on class in Svelte

我正在尝试使用 Svelte 对方程式进行一些条件样式设置和突出显示。虽然我已成功将全局静态样式应用于 class,但我无法弄清楚在事件发生时如何执行此操作(例如 class 的一个实例悬停在上方)。

我是否需要创建一个存储值(即当 class 悬停时设置为 true 的一些布尔值)以使用条件样式?或者我可以像下面的示例那样编写一个函数来定位 class 的所有实例吗?我有点不清楚为什么在样式中定位 class 需要 :global(classname) 格式。

App.svelte

<script>
    // import Component
    import Katex from "./Katex.svelte"
    
    
    
    // math equations
    const math1 = "a\htmlClass{test}{x}^2+bx+c=0";
    const math2 = "x=-\frac{-b\pm\sqrt{b^2-4ac}}{2a}";
    const math3 = "V=\frac{1}{3}\pi r^2 h";
    
    // set up array and index for reactivity and initialize
    const mathArray = [math1, math2, math3];
    let index = 0;
    $: math = mathArray[index];
    
    // changeMath function for button click
    function changeMath() {
        // increase index
        index = (index+1)%3;
    }
    
    function hoverByClass(classname,colorover,colorout="transparent")
    {
        var elms=document.getElementsByClassName(classname);
        console.log(elms);
        for(var i=0;i<elms.length;i++)
        {
            elms[i].onmouseover = function()
            {
                for(var k=0;k<elms.length;k++)
                {
                    elms[k].style.backgroundColor=colorover;
                }
            };
            elms[i].onmouseout = function()
            {
                for(var k=0;k<elms.length;k++)
                {
                    elms[k].style.backgroundColor=colorout;
                }
            };
        }   
    }   
hoverByClass("test","pink");
</script>

<h1>KaTeX svelte component demo</h1>

<h2>Inline math</h2>
Our math equation: <Katex {math}/> and it is inline.

<h2>Displayed math</h2>
Our math equation: <Katex {math} displayMode/> and it is displayed.

<h2>Reactivity</h2>
<button on:click={changeMath}>
    Displaying equation {index}
</button>

<h2>Static math expression within HTML</h2>
<Katex math={"V=\pi\textrm{ m}^3"}/>
<style>
    :global(.test) {
    color: red
    }
</style>

Katex.svelte

<script>
    import katex from "katex";
    export let math;
    export let displayMode = false;
    
    const options = {
        displayMode: displayMode,
        throwOnError: false,
        trust: true
    }
    
    $: katexString = katex.renderToString(math, options);
</script>

<svelte:head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css" integrity="sha384-AfEj0r4/OFrOo5t7NnNe46zW/tFgW6x/bCJG8FqQCEo3+Aro6EYUG4+cU+KJWu/X" crossorigin="anonymous">
</svelte:head>

{@html katexString}

如果我理解正确的话,你有一个包含任意嵌套元素的 DOM 结构,你会想要突出显示结构中共享相同 class.

的部分

所以你会有这样的结构:

<div>
  <p>This is some text <span class="a">highlight</span></p>
  <span class="a">Another highlight</span>
  <ul>
   <li>Some listitem</li>
   <li class="a">Some listitem</li>
   <li class="b">Some listitem</li>
   <li class="b">Some listitem</li>
  </ul>
</div>

并且如果您 select 具有 class="a" 的元素 所有 元素都应突出显示,无论它们在文档中的位置如何。这种任意放置使得无法在 select 或 css 中使用同级。

这个没有简单的解决办法,但我会给你我的尝试:

这是带有一些解释的完整代码

<script>
    import { onMount } from 'svelte'

    let hash = {}
    let wrapper
    
    onMount(() => {
        [...wrapper.querySelectorAll('[class]')].forEach(el => {
            if (hash[el.className]) return
            else hash[el.className] = [...wrapper.querySelectorAll(`[class="${el.className}"]`)]
        })
                
        Object.values(hash).forEach(nodes => {
            nodes.forEach(node => {
                node.addEventListener('mouseover', () => nodes.forEach(n => n.classList.add('hovered')))
                node.addEventListener('mouseout', () => nodes.forEach(n => n.classList.remove('hovered')))
            })
        })
    })
</script>

<div bind:this={wrapper}>
    <p>
        Blablabla <span class="a">AAA</span>
    </p>
    <span class="a">BBBB</span>
    <ul>
        <li>BBB</li>
        <li class="a b">BBB</li>
        <li class="b">BBB</li>
        <li class="b">BBB</li>
    </ul>
</div>

<style>
    div :global(.hovered) {
        background-color: red;
    }
</style>

我做的第一件事是使用 bind:this 获取环绕元素(在您的情况下,您会将其放在 {@html katexString} 周围,这将使突出显示仅应用于 这个特定的子树。

执行 querySelector 是一项复杂的操作,因此我们将在 onMount 期间将所有相关节点收集到一种哈希表中(这种假设内容永远不会改变,但由于它是用 @html 渲染我相信这样做是安全的)。

如您在 onMount 中所见,我使用 wrapper 元素将 selector 限制在页面的这一部分,即比检查整个文档快得多,而且可能正是您想要的。

我不完全确定你想做什么,但为了简单起见,我只是抓住每个有 class 的后代,并为每个 class 创建一个散列部分。如果你只想要某些 classes 你可以在这里写出一堆 selectors:

hash['selector-1'] = wrapper.querySelectorAll('.selector-1');
hash['selector-2'] = wrapper.querySelectorAll('.selector-2')];
hash['selector-3'] = wrapper.querySelectorAll('.selector-3');

创建此哈希表后,我们可以遍历每个 selector,并将两个事件侦听器附加到该 selector 的所有元素。一个 mouseover 事件,然后再次将新的 class 应用于它的每个伙伴。 mouseout 再次删除此 class。

这仍然意味着您必须添加 hovered class。由于 class 未在标记中使用,它将被 Svelte 删除,除非您使用 :global() ,因为您自己发现了这一点。拥有全局 classes 确实不是那么好,因为您可能会在代码的其他地方产生意想不到的效果,但是您可以像我在上面的代码中那样对其进行范围限制。

div > :global(.hovered) { background-color: red; }

会加工成

div.svelte-12345 .hovered { background-color: red; }

因此红色背景将仅应用于此特定 div 内的 .hovered 元素,而不会泄漏到整个代码库。

Demo on REPL

这里同样适用于使用您的代码并改为使用文档范围的 querySelector(如果需要,您可能仍然可以通过将绑定提高一级并将此节点传递到组件中来进行限制) Other demo on REPL