按钮根据其他按钮更改颜色。

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

buttons that change color based on other buttons

问题

我正在尝试修改我的程序,以便在点击四个按钮中的一个时,其他三个按钮会取消选中,但我不确定该怎么做。

在我的程序中,有16个像素,每个像素可以设置为00、01、10或11。然后,将正确的值输出到一个数组中,可以将其记录在控制台中或保存在文件中。我能够点击和取消点击像素,并改变发送到数组的值,但我无法弄清楚如何根据一个按钮中的操作来改变同一组中其他按钮的颜色。是否有一种方法可以根据一个按钮中的操作为按钮组制定颜色?即使不是代码,任何建议都将非常有帮助。(最终我将会有512个这样的像素)。谢谢!

以下是fiddle链接,因为代码很长:https://jsfiddle.net/q6rwfvua/

<div class="row">
    <div class="col"> 像素1
        <div class="row"><div class="btn-group-vertical-sm">
                <button name="myBtn" data-num="0" id="b1"> 00</button>
                <button name="myBtn1" data-num="0" id="b1"> 01</button>
            </div></div>
        <div class="row"><div class="btn-group-vertical-sm">
                <button name="myBtn2" data-num="0" id="b1"> 10</button>
                <button name="myBtn3" data-num="0" id="b1"> 11</button>
            </div></div>
    </div> <!--end of col -->
</div>
英文:

I am trying to modify my program so that when one of four buttons is clicked, the other three buttons get unclicked, but I am not sure what to do.

In my program, there are 16 pixels, and each pixel can be set to either 00, 01, 10, or 11. Then the correct value is output to an array, which can be logged to the console or saved in a file. I am able to click and unclick the pixels and change the values sent to the array, but I can not figure out how to change the color of other buttons in a group based on one of the buttons in a group. Is there some sort of way to make a color for button groups based on maybe the action taken in one of the buttons? Any suggestions even if not code, would be helpful. (eventually I will have 512 of these pixels). Thanks!

Here is the fiddle as the code is long: https://jsfiddle.net/q6rwfvua/

&lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col&quot;&gt; Pixel 1
        &lt;div class=&quot;row&quot;&gt;&lt;div class=&quot;btn-group-vertical-sm&quot;&gt;
                &lt;button name=&quot;myBtn&quot; data-num=&quot;0&quot; id=&quot;b1&quot;&gt; 00&lt;/button&gt;
                &lt;button name=&quot;myBtn1&quot; data-num=&quot;0&quot; id=&quot;b1&quot;&gt; 01&lt;/button&gt;
            &lt;/div&gt;&lt;/div&gt;
        &lt;div class=&quot;row&quot;&gt;&lt;div class=&quot;btn-group-vertical-sm&quot;&gt;
                &lt;button name=&quot;myBtn2&quot; data-num=&quot;0&quot; id=&quot;b1&quot;&gt; 10&lt;/button&gt;
                &lt;button name=&quot;myBtn3&quot; data-num=&quot;0&quot; id=&quot;b1&quot;&gt; 11&lt;/button&gt;
            &lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt; &lt;!--end of col --&gt;

答案1

得分: 2

这个答案可能看起来有点长,但我想介绍一些可能有助于你长期前端开发的新概念。它使用循环创建标记(如果你正在创建512个框,特别有用!),并通过使用一些不错的DOM方法缩短JavaScript代码。

首先让我们检查每个“框”(包括标签和按钮集)的核心HTML。目前,它是四个嵌套的div,其中四个按钮分为两个部分。

按钮有一个名称,一个ID和一个数据属性。我们可以将其简化为只有一个表示该按钮代表的数字的数据属性,并将组ID移到父元素。这样可以节省一些空间/混乱,并使HTML更易于处理。对于每个“框”,我们最终得到这个:

<div class="box" data-id="1">
  <span>Pixel 1</span>
  <div class="buttons">
    <button data-num="0">00</button>
    <button data-num="1">01</button>
    <button data-num="2">10</button>
    <button data-num="3">11</button>
  </div>
</div>

正如你在示例中看到的,我们可以利用这个结构。为了节省大量HTML空间,我们可以使用循环使用模板/字符串字面量创建所有框。

循环和使用模板字符串是第一个概念。

第二个概念是事件委托。我们可以不是将事件侦听器附加到所有元素上,而是明智地将其添加到主父容器上,并让它从其子元素那里捕获事件,因为它们在DOM中“冒泡”上升。这也适用于控制按钮(例如“将所有设置为2”)。

当侦听器首先捕获事件时,它首先检查它是否来自我们有兴趣处理的子元素(例如来自按钮),然后处理程序中的代码可以处理来自按钮以及其父“框”元素的信息。

在这种情况下,它将从数据集中获取num值,然后找到其closest“框”父元素并从其数据属性中获取其pixelId值。从那里,它可以获取其直接父元素(具有buttons类的元素),然后获取该元素的所有按钮。

然后根据num值,我们可以在迭代它们时开始向这些按钮添加/删除“绿色”类。

最后,一旦完成,我们可以使用pixelId值更新像素数组,该值用作索引以存储num值。

这些是相对容易对你的代码/标记进行的更改。此外的内容仅涉及可能对CSS进行的更改。

(我在这里引入的CSS是CSS GridFlexbox。它们使得处理你这样的布局稍微容易一些,几乎没有额外的开销。)

英文:

This answer may seem long for what could be a short reply but I want to introduce a few new concepts that might help your front-end development in the long run. It uses a loop to create the markup (particularly useful if you're creating 512 boxes!), and shortens the JavaScript code by using a couple of nice DOM methods.

First let's examine your core HTML for each "box" (comprises the label and the set of buttons). At the moment it's four nested divs with the four buttons separated into two sections.

Buttons have a name, an id, and a data attribute. We can pare that back to just one data attribute for the number that button represents, and move the group id to the parent element. This saves a little space/clutter, and makes the HTML easier to work with. For each "box" we end up with this:

&lt;div class=&quot;box&quot; data-id=&quot;1&quot;&gt;
  &lt;span&gt;Pixel 1&lt;/span&gt;
  &lt;div class=&quot;buttons&quot;&gt;
    &lt;button data-num=&quot;0&quot;&gt;00&lt;/button&gt;
    &lt;button data-num=&quot;1&quot;&gt;01&lt;/button&gt;
    &lt;button data-num=&quot;2&quot;&gt;10&lt;/button&gt;
    &lt;button data-num=&quot;3&quot;&gt;11&lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;

As you'll see in the example we can use this structure to our advantage. To save a lot of HTML real estate we can use a loop to create all of the boxes using a template/string literals.

Looping and using a template string is the first concept.

The second concept is event delegation. Instead of attaching event listeners to all of the elements we can judiciously add one to main parent container and have that catch events from its child elements as they "bubble up" the DOM. This applies to the control buttons (ie "Set all to 2") as well.

When the listener catches an event first it checks to see if its from a child element that we're interested in processing (ie from a button), and then the code in the handler can work on what do with the information it can get from the button, and it's parent "box" element.

In this case it will grab the num value from its dataset, and then find its closest "box" parent element and grab its pixelId value from its data attribute. From there it can get its immediate parent (the element with the buttons class), and then grab all of that element's buttons.

Then based on the num value we can start adding/removing a "green" classe from the those buttons as we iterate over them.

Finally, once that's complete, we can update the pixels array using the pixelId value for the index to store the num value.

These are alterations you can make to your code/markup relatively easily. The rest of this just pertains to changes you might make to the CSS.

(The CSS I've introduced here is CSS Grid and Flexbox. They just make working with a layout such as yours a little easier with very little extra overhead.)

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

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

// Cache the grid element, and add
// an event listener to it
const grid = document.querySelector(&#39;.grid&#39;);
grid.addEventListener(&#39;click&#39;, handleGrid);

// Cache the controls element, and add
// an event listener to it
const controls = document.querySelector(&#39;.controls&#39;);
controls.addEventListener(&#39;click&#39;, handleControls);


// Create an array with 16 spaces each
// filled with zero 
const pixels = new Array(16).fill(0);

// Array to cache the HTML as its built
const html = [];

// Iterate from 0 to 15, and on each iteration
// create a template string that holds the HTML
// for one &quot;box&quot; - a box holds the box title
// (ie &quot;Pixel 1&quot;, and a group of four boxes)
// The element with the box class holds the &quot;id&quot; data attribute
// which we&#39;ll use to target the index of the pixels
// array, and each button has a &quot;num&quot; data attribute
// which we use to populate the pixel array at the right index
for (let i = 0; i &lt; 16; i++) {
  const pixel = `
    &lt;div class=&quot;pixel&quot; data-id=&quot;${i}&quot;&gt;
      &lt;span&gt;Pixel ${i + 1}&lt;/span&gt;
      &lt;div class=&quot;buttons&quot;&gt;
        &lt;button data-num=&quot;0&quot;&gt;00&lt;/button&gt;
        &lt;button data-num=&quot;1&quot;&gt;01&lt;/button&gt;
        &lt;button data-num=&quot;2&quot;&gt;10&lt;/button&gt;
        &lt;button data-num=&quot;3&quot;&gt;11&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  `;
  
  // On each iteration we push that string into
  // the html array
  html.push(pixel);
}

// Once the iteration is complete join up the
// array into one HTML string and assign it to the
// innerHTML of the grid element
grid.innerHTML = html.join(&#39;&#39;);


// When the grid element catches an event from one
// of its child elements it...
function handleGrid(e) {
  
  // 1) Checks that it&#39;s a button element
  if (e.target.matches(&#39;button&#39;)) {
    
    // Takes the &quot;id&quot; from box&#39;s data attribute, and the
    // &quot;num&quot; from the button&#39;s data attribute
    const pixelId = Number(e.target.closest(&#39;.pixel&#39;).dataset.id);
    const num  = Number(e.target.dataset.num);
    
    // Caches the button&#39;s closest element with
    // the &quot;buttons&quot; class (ie its parent element), and
    // selects all of the parent&#39;s child buttons
    const parent = e.target.closest(&#39;.buttons&#39;);
    const buttons = parent.querySelectorAll(&#39;button&#39;);
    
    // Loops over each button removing the colour classes.
    buttons.forEach(button =&gt; {
      button.classList.remove(&#39;green&#39;, &#39;red&#39;);
    });
    
    // Change the class for the clicked element
    if (num === 0) {
      e.target.classList.add(&#39;red&#39;);
    } else {
      e.target.classList.add(&#39;green&#39;);
    }

    // Update the pixel array! If the clickded button&#39;s
    // number is greater than zero set the value at the
    // index specified by the pixelId to the number, otherwise
    // set it to zero
    pixels[pixelId] = num &gt; 0 ? num: 0;
    
    console.log(JSON.stringify(pixels));

  }

}

// Handler gets the number from the control button
// removes all the green classes from all the buttons,
// and then applies the class to all the buttons that match
// the number
function handleControls(e) {
  
  if (e.target.matches(&#39;button&#39;)) {
    
    const num = Number(e.target.dataset.num);    
    
    const allButtonSelector = &#39;.buttons button&#39;;
    const allButtons = grid.querySelectorAll(allButtonSelector);
    
    allButtons.forEach(button =&gt; {
      button.classList.remove(&#39;green&#39;)
    });
    
    const singleButtonSelector = `button[data-num=&quot;${num}&quot;]`;
    const singleButtons = grid.querySelectorAll(singleButtonSelector);
    
    singleButtons.forEach(button =&gt; {
      button.classList.add(&#39;green&#39;);
    });
  
  }

}

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

.grid, .buttons { display: grid; width: fit-content; height: fit-content; }
.grid { grid-template-rows: 60px 1fr; gap: 15px; grid-auto-flow: column; width: 580px; }
.buttons { margin-top: 0.25rem; grid-template-columns: 22px 1fr; gap: 3px; grid-auto-flow: row; aspect-ratio: 1; width: fit-content; }
.buttons button { display: flex; justify-content: center; align-items: center; width: 22px; }
.buttons button:hover { cursor: pointer; }
.box { display: flex; flex-direction: column; justify-content: center; align-items: center; }
.green, .red { color: white; }
.red { background-color: red; }
.green { background-color: green; }
.controls { margin-top: 1rem; }
.controls button { margin-left: 0.25rem; }
.as-console-wrapper { max-height: 20px !important; bottom: 0; }

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

&lt;section class=&quot;grid&quot;&gt;&lt;/section&gt;
&lt;section class=&quot;controls&quot;&gt;
  &lt;button data-num=&quot;0&quot;&gt;Set all to 0&lt;/button&gt;
  &lt;button data-num=&quot;1&quot;&gt;Set all to 1&lt;/button&gt;
  &lt;button data-num=&quot;2&quot;&gt;Set all to 2&lt;/button&gt;
  &lt;button data-num=&quot;3&quot;&gt;Set all to 3&lt;/button&gt;
&lt;/section&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年5月15日 06:06:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76249874.html
匿名

发表评论

匿名网友

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

确定