【问题标题】:Conditional styling on class in SvelteSvelte 中类的条件样式
【发布时间】:2021-10-13 11:26:58
【问题描述】:

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

我是否需要创建一个存储值(即当类悬停时设置为 true 的一些布尔值)才能使用条件样式?或者我可以像下面的示例中那样编写一个针对该类的所有实例的函数吗?我有点不清楚为什么在样式中定位一个类需要: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}

【问题讨论】:

  • 全局是必需的,因为该类不是使用 Svelte 有条件地添加的,并且在您的标记中不存在。但是,是否有某些原因您不只使用 CSS? “当类的一个实例悬停时”在 CSS 中看起来像这样:.className:hover {styling} 并且当该类悬停时将一直工作,不需要 JS。
  • 感谢您的回复。我试图突出显示同一类的多个实例(即,如果用户将鼠标悬停在一个“x”上,则“x”的所有实例都应该应用条件样式,而不仅仅是悬停的那个)。
  • 您也可以定位兄弟姐妹。 .className:hover ~ .className, .className:hover {styling}

标签: javascript html css svelte svelte-component


【解决方案1】:

如果我理解正确,您有一个带有任意嵌套元素的 DOM 结构,并且您希望突出显示共享同一类的结构部分。

所以你会有这样的结构:

<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>

如果你选择一个带有class="a"的元素,所有元素都应该被突出显示,无论它们在文档中的什么位置。这种任意放置使得在 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} 周围,这将使突出显示仅应用于this特定的子树。

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

正如您在onMount 中看到的那样,我使用 wrapper 元素将选择器限制在页面的这一部分,这比检查整个文档要快得多,可能是无论如何你都想要。

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

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

创建此哈希表后,我们可以遍历每个选择器,并将两个事件侦听器附加到该选择器的所有元素。一个 mouseover 事件,它将再次将一个新类应用到它的每个伙伴。还有一个 mouseout 会再次移除这个类。

这仍然意味着您必须添加 hovered 类。由于该类未在标记中使用,它将被 Svelte 删除,除非您使用 :global(),因为您发现自己。拥有全局类确实不是很好,因为您可能会在代码的其他地方产生意想不到的影响,但是您可以像我在上面的代码中那样设置它的范围。

线

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

会被处理成

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

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

Demo on REPL

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

【讨论】:

  • 这是一种巧妙的做法;感谢您的详细回复!对于这个特定的用例,内容不会改变,因此解决方案按原样工作。我很好奇你是否可以做类似的事情来应用基于依赖节点的条件样式。
猜你喜欢
  • 2021-07-06
  • 2021-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-29
  • 2020-11-15
  • 2021-08-27
相关资源
最近更新 更多