构建反应组件

2025-06-07

构建反应组件

我们都熟悉 dev.to 的“反应组件”(尽管我仍然不确定独角兽是用来做什么的!)这里有一个关于如何创建“反应组件”的简短教程——使用不使用 JavaScipt。

让我们从 CSS 版本开始吧!


标记

我们将把每个反应包装在 中,并在 后<label>添加<svg>和一个空的<span><input type="checkbox">

<label aria-label="React with heart">
  <input type="checkbox" name="reaction-heart" value="75" style="--c:75" />
  <svg></svg>
  <span></span>
</label>
Enter fullscreen mode Exit fullscreen mode

我们<input type="checkbox">将使用 来控制state value


图标

在 dev.to 上,当你对某事做出“反应”时,会使用两种不同的图标。“点赞”操作会显示一颗空心和一颗实心。“独角兽”和“书签”操作也是如此。

有人可能会说,只要稍微修改一下设计,图标就能直接切换 SVG 样式fillstroke或者stroke-width——但我们还是保留两个图标吧。我们会把<g>它们组合到一个 SVG 中:

<svg viewBox="0 0 24 24">
  <g><path d="M21.179 12.794l.013.014L12 22l-9.192-9.192.013-.014A6.5 6.5 0 0112 3.64a6.5 6.5 0 019.179 9.154zM4.575 5.383a4.5 4.5 0 000 6.364L12 19.172l7.425-7.425a4.5 4.5 0 10-6.364-6.364L8.818 9.626 7.404 8.21l3.162-3.162a4.5 4.5 0 00-5.99.334l-.001.001z"></path></g>
  <g><path d="M2.821 12.794a6.5 6.5 0 017.413-10.24h-.002L5.99 6.798l1.414 1.414 4.242-4.242a6.5 6.5 0 019.193 9.192L12 22l-9.192-9.192.013-.014z"></path></g>
</svg>
Enter fullscreen mode Exit fullscreen mode

在 CSS 中,我们可以使用:checked伪选择器在两个图标之间切换(在<g>标签中):

[name*="reaction-"]:checked + svg g:first-of-type,
[name*="reaction-"]:not(:checked) + svg g:last-of-type {
  opacity: 0;
}
[name*="reaction-"]:checked + svg g:last-of-type {
  opacity: 1;
}
Enter fullscreen mode Exit fullscreen mode

太棒了,现在我们可以使用复选框在两个图标之间切换了,让我们添加一个计数器!你注意到style="--c:75"标记里的 了吗?

我们将使用它作为 CSS 计数器:

counter-reset: reaction var(--c);
Enter fullscreen mode Exit fullscreen mode

不幸的是,我们不能使用value-attribute,如下所示:

counter-reset: reaction attr(value);
Enter fullscreen mode Exit fullscreen mode

– 因此我们必须使用那个额外的自定义属性--c作为初始值。

然后,我们再次挂接到:checked-selector:

[name*="reaction-"]:checked {
  counter-increment: reaction;
}
Enter fullscreen mode Exit fullscreen mode

<span>标记中的空白现在将发挥它的作用:

span::after {
  content: counter(reaction);
}
Enter fullscreen mode Exit fullscreen mode

但为什么是空的 <span>?这是因为我们必须将计数器添加为伪元素内容(::before::after)。

不幸的是,我们不能向中添加伪元素<input type="checkbox">,因为<input>-tags 是标签组的一部分,不能有子标签(又名“自闭合”标签)或伪内容(实际上它们可以在 Chrome 和 Safari 中,但这不是规范的一部分!)。

剩下的只是一些样式。以下是 Codepen 上纯 CSS 的示例:


JavaScript

虽然纯 CSS 版本很酷,但不太实用。你可能需要把响应存储在某个地方!

让我们从 CSS 中删除与计数器相关的内容,并style="--c"从标记中删除 -part。我们将反应包装在一个 中<form id="react">,并使用 -eventListener 监听更改onchange

react.addEventListener('change', (e) => {
  const t = e.target;
  t.parentNode.lastElementChild.innerText = t.value = t.value - 0 + (t.checked ? 1 : -1);
});
Enter fullscreen mode Exit fullscreen mode

这个小片段将从当前反应中添加减去 1(一) ,然后将设置为该valueinnerText<span>

在此代码片段中,您可以添加fetch()(带有POST)来存储当前反应。

例如,在 dev.to 上,JSON有一个 small -object POST

{
  result: "create",
  category: "like"
}
Enter fullscreen mode Exit fullscreen mode

例如,使用 JavaScript:

如果要将所有元素的文本设置<span>values <input>,请使用以下小代码片段来迭代elements的集合<form>

[...react.elements].forEach(t => t.parentNode.lastElementChild.innerText = t.value);
Enter fullscreen mode Exit fullscreen mode

就是这样!最近,dev.to 上有一个“星级评定”挑战(我的参赛作品是“使用单一输入心情选择器进行星级评定”)。

观察其他开发人员如何解决问题总是很有趣的,所以如果您修改了我的示例,请在评论中分享链接,或者 - 甚至更好 - 制作您自己的“反应组件”!

文章来源:https://dev.to/madsstoumann/building-a-reaction-component-2noe
PREV
时钟和倒计时:CSS 和 JavaScript 中的计时
NEXT
技术面试失败后该怎么办?