元素在React中具有悬停行为时跨<li>元素上的文本

huangapple go评论59阅读模式
英文:

<mark> text across <li> elements with hover behavior in React

问题

如果我有这样的HTML/JSX:

<ul>
  <li>第一个项目</li>
  <li>第二个项目</li>
</ul>

而我想要突出显示一个"跨越"多个列表元素的范围,如下所示:

<ul>
  <li>第一个项目</li>
  <li>第二个项目</li>
</ul>

最后,我想要添加一些行为,使得在第一个<mark>标签上悬停会触发第二个<mark>标签上的效果,反之亦然。从用户的角度来看,它应该看起来和感觉起来像一个单独的<mark>标签。

这是否可以仅使用CSS/Tailwind来实现?根据我目前所见,兄弟元素~选择器只能用于影响后面的元素。在Tailwind中的peer类似乎也是如此。

如果需要JavaScript,是否可以指导我正确的方向?值得一提的是,这是一个React项目,因此可能存在一些直接操作DOM的注意事项。

英文:

Suppose I have HTML / JSX like this:

&lt;ul&gt;
  &lt;li&gt;First bullet point&lt;/li&gt;
  &lt;li&gt;Second bullet point&lt;/li&gt;
&lt;/ul&gt;

and I want to highlight a range that "spans" multiple list elements "contiguously":

&lt;ul&gt;
  &lt;li&gt;First bullet &lt;mark&gt;point&lt;/mark&gt;&lt;/li&gt;
  &lt;li&gt;&lt;mark&gt;Second bullet&lt;/mark&gt; point&lt;/li&gt;
&lt;/ul&gt;

Lastly, I'd like to add behaviour such that hovering over the first &lt;mark&gt; tags will trigger something for the second &lt;mark&gt; tags and vice versa. From the user's perspective, it should look and feel like a single &lt;mark&gt; tag.

Can this be done exclusively with CSS / Tailwind? Based on what I've seen so far, the sibling ~ combinator can only be used on earlier elements to affect later elements. The same appears to be true for the peer class in Tailwind.

If Javascript is required, can someone point me in the right direction? FWIW, this is for a React project so there may be some caveats to manipulating the DOM directly.

答案1

得分: 1

  1. 如果悬停在任何标记上也会“悬停”在每个其他标记上,那么这是一个简单的 has() 调用。
ul:has(mark:hover) mark {
  background-color: red;
}
  1. 如果只有悬停在一个标记上会“悬停”在相邻的标记上,那么这就会复杂一些。
li mark:hover,
li:has(mark:last-child:hover) + li > mark:first-child,
li:has(mark:last-child):has(+ li > mark:first-child:hover) mark {
  background-color: red;
}
  1. 由于 :has() 在 Firefox 中默认未启用(截至版本109),这里有一个使用 JavaScript 的解决方法。
const ul = document.querySelector("ul");

const removeActive = function (evt) {
  const active = evt.currentTarget.querySelector("mark.active");
  if (active) active.classList.remove("active");
}

ul.addEventListener("mouseover", function (evt) {
  removeActive(evt);
  let elem = null;

  const mark = evt.target.closest("mark");
  if (!mark) return;
  
  const li = mark.closest("li");
  
  if (!mark.previousSibling) {
    const prevLi = li.previousElementSibling;
    elem = prevLi && prevLi.lastChild;
  } else if (!mark.nextSibling) {
    const nextLi = li.nextElementSibling;
    elem = nextLi && nextLi.firstChild;
  }
  
  if (elem && elem.nodeName == "MARK") {
    elem.classList.add("active");
  }
});

ul.addEventListener("mouseleave", removeActive);
li mark:hover,
li mark.active {
  background-color: red;
}

以上是你要翻译的内容。

英文:
  1. If hovering over any mark will also "hover" every other mark, then it is a simple has() call.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->

ul:has(mark:hover) mark {
  background-color: red;
}

<!-- language: lang-html -->

&lt;ul&gt;
  &lt;li&gt;&lt;span&gt;First bullet &lt;/span&gt;&lt;mark&gt;point&lt;/mark&gt;&lt;/li&gt;
  &lt;li&gt;&lt;mark&gt;Second bullet&lt;/mark&gt;&lt;span&gt; point&lt;/span&gt;&lt;/li&gt;
  &lt;li&gt;&lt;span&gt;Third bullet &lt;/span&gt;&lt;mark&gt;point&lt;/mark&gt;&lt;/li&gt;
  &lt;li&gt;&lt;mark&gt;Fourth bullet&lt;/mark&gt;&lt;span&gt; point&lt;/span&gt;&lt;/li&gt;
  &lt;li&gt;&lt;span&gt;The &lt;/span&gt;&lt;mark&gt;Fifth bullet&lt;/mark&gt;&lt;span&gt; point&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;

<!-- end snippet -->

  1. If hovering over a mark only "hovers" marks that are contiguous, then it is a bit more complicated.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->

li mark:hover,
li:has(mark:last-child:hover) + li &gt; mark:first-child,
li:has(mark:last-child):has(+ li &gt; mark:first-child:hover) mark {
  background-color: red;
}

<!-- language: lang-html -->

&lt;ul&gt;
  &lt;li&gt;&lt;span&gt;First bullet &lt;/span&gt;&lt;mark&gt;point&lt;/mark&gt;&lt;/li&gt;
  &lt;li&gt;&lt;mark&gt;Second bullet&lt;/mark&gt;&lt;span&gt; point&lt;/span&gt;&lt;/li&gt;
  &lt;li&gt;&lt;span&gt;Third bullet &lt;/span&gt;&lt;mark&gt;point&lt;/mark&gt;&lt;/li&gt;
  &lt;li&gt;&lt;mark&gt;Fourth bullet&lt;/mark&gt;&lt;span&gt; point&lt;/span&gt;&lt;/li&gt;
  &lt;li&gt;&lt;span&gt;The &lt;/span&gt;&lt;mark&gt;Fifth bullet&lt;/mark&gt;&lt;span&gt; point&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;

<!-- end snippet -->

  1. Since :has() is not enabled by default on Firefox (as of v109), here's a workaround using JavaScript.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const ul = document.querySelector(&quot;ul&quot;);

const removeActive = function (evt) {
  const active = evt.currentTarget.querySelector(&quot;mark.active&quot;);
  if (active) active.classList.remove(&quot;active&quot;);
}

ul.addEventListener(&quot;mouseover&quot;, function (evt) {
  removeActive(evt);
  let elem = null;

  const mark = evt.target.closest(&quot;mark&quot;);
  if (!mark) return;
  
  const li = mark.closest(&quot;li&quot;);
  
  if (!mark.previousSibling) {
    const prevLi = li.previousElementSibling;
    elem = prevLi &amp;&amp; prevLi.lastChild;
  } else if (!mark.nextSibling) {
    const nextLi = li.nextElementSibling;
    elem = nextLi &amp;&amp; nextLi.firstChild;
  }
  
  if (elem &amp;&amp; elem.nodeName == &quot;MARK&quot;) {
    elem.classList.add(&quot;active&quot;);
  }
});

ul.addEventListener(&quot;mouseleave&quot;, removeActive);

<!-- language: lang-css -->

li mark:hover,
li mark.active {
  background-color: red;
}

<!-- language: lang-html -->

&lt;ul&gt;
  &lt;li&gt;First bullet &lt;mark&gt;point&lt;/mark&gt;&lt;/li&gt;
  &lt;li&gt;&lt;mark&gt;Second bullet&lt;/mark&gt; point&lt;/li&gt;
  &lt;li&gt;Third bullet &lt;mark&gt;point&lt;/mark&gt;&lt;/li&gt;
  &lt;li&gt;&lt;mark&gt;Fourth bullet&lt;/mark&gt; point&lt;/li&gt;
  &lt;li&gt;The &lt;/span&gt;&lt;mark&gt;Fifth bullet&lt;/mark&gt;&lt;span&gt; point&lt;/li&gt;
&lt;/ul&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年2月16日 02:58:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75464335.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定