改变 Stimulus JS 类值?

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

Stimulus JS: Changing stimulus class values?

问题

我有一个 Stimulus JS 控制器,其中有一个名为 colorKey 的目标。ColorKey 可以是 5 种不同的颜色之一,通过添加 5 种不同的 CSS 类来设置('bg-green'、'bg-blue' 等)。

根据我对 StimulusJS 文档中的 css classes 部分的阅读,似乎我应该使用 classList.add/classList.remove 调用来更新颜色。这样做是有效的,但这意味着我要运行以下代码:

this.colorKeyTarget.classList.remove(this.orangeClass)
this.colorKeyTarget.classList.remove(this.redClass)
this.colorKeyTarget.classList.remove(this.blueClass)
this.colorKeyTarget.classList.remove(this.blackClass)
this.colorKeyTarget.classList.add(this.greenClass)

这显然不是一种优雅的方法。

我希望/假设我可以像这样在 DOM 中做一些事情:

<div data-bg-color-class="bg-orange"></div>

然后只需调用:

this.bgColorClass = "bg-green"

而不是上面的繁琐操作。我假设有一种类似于后一种方法的方式,但我找不到是什么。有人有关于通过 Stimulus 分配 5 种类之一给 DOM 的最佳实践建议,而不涉及在添加所需状态之前删除每种可能状态的建议吗?

英文:

I have a Stimulus JS controller with a target called colorKey. ColorKey can be one of 5 different colors, set by adding 1 of 5 different CSS classes ('bg-green', 'bg-blue', etc)

From my reading of the css classes section of the stimulusJS docs, it seems I'm expected to update the color by using classList.add/classList.remove calls. That works, but it means I'm running:

this.colorKeyTarget.classList.remove(this.orangeClass)
this.colorKeyTarget.classList.remove(this.redClass)
this.colorKeyTarget.classList.remove(this.blueClass)
this.colorKeyTarget.classList.remove(this.blackClass)
this.colorKeyTarget.classlist.add(this.greenClass)

which isn't exactly elegant to put it mildly.

I was hoping/assuming I could do something like:

&lt;div data-bg-color-class=&quot;bg-orange&quot;&gt;&lt;/div&gt;

in the dom, and then simply call:

this.bgColorClass = &quot;bg-green&quot;

instead. I assume there's some way to do something similar to the latter, but I can't figure out what it is. Anyone have any suggestions on best practices for assigning one of 5 classes to a DOM via stimulus in a way that doesn't involve removing every possible state before adding the one state you want?

答案1

得分: 2

根据你想要实现的目标,Stimulus CSS Classes 方法可能不太合适。看起来你更像是在设置一个背景预览选择器。

你可以在这里使用类,但正如注意到的那样,随着选项的增加,添加更多选项会变得有点复杂。类更适合用于诸如“加载/激活”类这样的东西,这是一小组离散状态,也可以通过类名更改来反映。

相反,你可能希望在这里使用 Stimulus 值的方法,以及一些更容易映射到关闭除所选项之外的所有其他选项的东西。

我建议使用 Stimulus Object,这是一个可以存储在控制器上的 JSON 字符串,可以轻松地映射键/值对。

示例

  • 在我们的 HTML 中,我们设置了所有颜色键及其适用类的 JSON 值。提醒一下,这必须是正确格式的 JSON,如果你在属性中使用 &quot;,你需要正确转义它。你的渲染库应该会为你做这个,但如果你手工编写这个值,双重检查输出。
  • 你也可以使用 Stimulus action params,这样可以更轻松地准备一个按钮或类似的东西来切换颜色。
  • 最后,我建议将目标的名称从 colorKey 更改为更简单的名称,因为你很可能在 HTML 的许多地方已经有了单词 color
&lt;div data-controller=&quot;bg-color&quot; data-bg-color-classes-value=&#39;{&quot;red&quot;: &quot;something-red&quot;,&quot;blue&quot;:&quot;something-borrowed&quot;,&quot;orange&quot;:&quot;something-new&quot;,&quot;black&quot;:&quot;bg-000000&quot;,&quot;green&quot;:&quot;i-choose-green&quot;}&#39;&gt;
  &lt;div data-bg-color-target=&quot;container&quot;&gt;
    内容!
  &lt;/div&gt;
  &lt;button data-action=&quot;bg-color#show&quot; data-bg-color-key-param=&quot;red&quot;&gt;Go Red!&lt;/button&gt;
  &lt;button data-action=&quot;bg-color#show&quot; data-bg-color-key-param=&quot;green&quot;&gt;Go Green!&lt;/button&gt;
&lt;/div&gt;
  • 在 JS 中,我们从 show 方法中提取出 key,可以从 CustomEvent detail 或 Action params 中提取出来。这可以根据你计划触发的方式进行多种不同的方式来完成。
  • show 方法中,我们在尝试更改 DOM 之前对一些事情进行了一些检查,如果有什么东西丢失,就会提前返回。
  • 我们读取整个对象值(Stimulus 会将其从 JSON 转换为对象),然后使用 Object.entries 映射键/值对,以添加类或删除类。这意味着如果你想要添加/删除颜色,唯一需要更改的代码就是值的 HTML 数据属性。
  • 控制器的其余部分对你有多少个颜色是不可知的,因此这使得它更具可重用性和灵活性。
class BgColor extends Controller {
  static targets = [&#39;container&#39;];
  static values = { classes: Object };
  
  show(event) {
    const { key } = event?.params || event?.detail || {}; // 从 Stimulus 动作参数或分派事件详细信息中提取键。
    const element = this.containerTarget;
    const classes = this.hasClassesValue ? this.classesValue : {};
    const currentColorClass = classes[colorKey];
    if (!currentColorClass || !element) return; // 忽略不匹配的类(也可以抛出错误)
    Object.entries(classes).forEach(([colorKey, value]) =&gt; {
      if (key === colorKey) {
        element.classList.add(value);
      } else {
        element.classList.remove(value);
      }
    });
  }
}
  • 提醒:如果你给出一个以空格分隔的字符串,classList.add/remove 将不起作用,它只会查看该字符串的第一部分。如果你期望你的类是类似于 "color color--blue" 的东西,你需要更改你对 classList.add/remove 的使用。类似 element.classList.add(...value.split(" ")); 的东西应该可以处理无论字符串以什么格式提供。
英文:

For what you are trying to achieve, the Stimulus CSS Classes approach may not be the most suitable. It seems like you are setting up something more like a background preview picker.

You could use classes here but as noted, it becomes a bit complex to add more and more options. Classes are better used for things like 'loading/active' classes, a small set of discrete states that can be reflected also by class name changes.

Instead, you may want a Stimulus value approach here and something that is easier to map through to switch all things off except something that is selected.

I recommend a Stimulus Object value, this is a JSON string that can be stored on the controller and can easily map key/value pairs.

Example

  • In our HTML we set up the JSON value for all the color keys and their applicable classes. A reminder that this MUST be correctly formatted JSON and if you are using &quot; for attributes, you will need to escape this correctly. Your rendering library should do this for you but if you are hand-writing this value, double check the output.
  • You can use the Stimulus action params also, making it easier to prepare a button or similar to toggle the colours.
  • Finally, I recommend revising the name of your target from colorKey to something simpler as you likely have the word color already in the HTML in many places.
&lt;div data-controller=&quot;bg-color&quot; data-bg-color-classes-value=&#39;{&quot;red&quot;: &quot;something-red&quot;,&quot;blue&quot;:&quot;something-borrowed&quot;,&quot;orange&quot;:&quot;something-new&quot;,&quot;black&quot;:&quot;bg-000000&quot;,&quot;green&quot;:&quot;i-choose-green&quot;}&#39;&gt;
  &lt;div data-bg-color-target=&quot;container&quot;&gt;
    CONTENT!
  &lt;/div&gt;
  &lt;button data-action=&quot;bg-color#show&quot; data-bg-color-key-param=&quot;red&quot;&gt;Go Red!&lt;/button&gt;
  &lt;button data-action=&quot;bg-color#show&quot; data-bg-color-key-param=&quot;green&quot;&gt;Go Green!&lt;/button&gt;
&lt;/div&gt;
  • In the JS, we wull out the key from the show method either at the CustomEvent detail or the Action params. This could be done a few different ways, depending on how you plan to trigger things.
  • In the show method, we do a few checks for things before we attempt to mutate the DOM, returning early if something is missing.
  • We read out the entire Object value (Stimulus will convert this from JSON to an object), then map through the key/value pairs using Object.entries to either add the class or remove the class. This means that the only code needing to be changed if you wanted to add/remove colours is the HTML data attribute for the value.
  • The rest of the Controller is agnostic to how many colours you have, making this more reusable and flexible in the process.
class BgColor extends Controller {
  static targets = [&#39;container&#39;];
  static values = { classes: Object };
  
  show(event) {
    const { key } = event?.params || event?.detail || {}; // destructure key from either Stimulus action params for dispatched event detail.
    const element = this.containerTarget;
    const classes = this.hasClassesValue ? this.classesValue : {};
    const currentColorClass = classes[colorKey];
    if (!currentColorClass || !element) return; // ignore unmatched class silently (could throw an error also)
    Object.entries(classes).forEach(([colorKey, value]) =&gt; {
      if (key === colorKey) {
        element.classList.add(value);
      } else {
        element.classList.remove(value);
      }
    });
  }
}
  • Reminder: classList.add/remove will not work if you give a space separated string, it only will look at the first part of that string. If you expect that your classes will be something like "color color--blue" you will need to change your usage of classList.add/remove. Something like element.classList.add(...value.split(&quot; &quot;)); should work no matter what format the string comes in.

huangapple
  • 本文由 发表于 2023年6月15日 19:24:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76481967.html
匿名

发表评论

匿名网友

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

确定