从所有 nodelist 元素中删除样式并仅添加到单击的元素 Vanilla JS

remove styles from all nodelist element and add only to clicked element Vanilla JS

我有多个 div,单击它们会添加一个边框并将它们放大一点。我正在使用 foreach 遍历所有元素,并在单击时删除每个元素的边框和比例 属性 除了单击的元素,我向其添加了边框和比例。 我的代码完全合乎逻辑并且应该可以工作,但出于某种原因我似乎无法理解,它只将样式应用于单击的元素而不是从其余元素中删除(就像我的代码所说的那样)。

JS

    document.querySelectorAll('.projcolorpick div').forEach(el => {
            el.onclick = (e) => {
                el.style.border = "none"
                el.style.transform  = "scale(1)"
                e.target.style.border = "2px solid #fff"
                e.target.style.transform = "scale(1.2)" 
                projcolor = e.target.style.background   
            }
        }) 
     } 

试一试...每个元素都需要一个 id 属性才能正常工作(过滤器部分 - 如果有唯一属性...)

    const list = Array.from(document.querySelectorAll('.projcolorpick div'));
    list.forEach(el => {
            el.addEventListener('click', (e) => {
                //code that affects the element you click on
                el.style.border = "2px solid #fff"
                el.style.transform = "scale(1.2)" 
                projcolor = e.target.style.background;
                list.filter(x=>x.id!=el.id).forEach(otherEl=>{
                    //code that affects the other elements you didn't click on
                    otherEl.style.border = "none"
                    otherEl.style.transform  = "scale(1)"
                });
            });
        }); 
     
    ```
edit:
fixed some typos.

forEach 仅适用于 Arrays,除非您另行配置。

querySelectorAll 不是 return 数组,而是 array-like 对象 (NodeLists)

要允许循环 NodeList 秒,请添加以下代码:

if (window.NodeList && !NodeList.prototype.forEach) { 
    NodeList.prototype.forEach = Array.prototype.forEach;
}


var nL = document.querySelectorAll('*');

console.log(nL instanceof NodeList); // true

你真的不需要每个 div 的 id 属性,我提倡使用 class-assignments 而不是改变它们的 individual 属性。您可以将实际的 DOM 元素相互比较,例如 c==ev.target,您可以在下面的代码中看到:

// === populate the page first ... ============================= START =
const cont=document.getElementById('container');
cont.innerHTML=
[...Array(3)].map(cp=>'<div class="projcolorpick">'+
  [...Array(8)].map(d=>{
    let hsl= "hsl("+Math.floor(Math.random()*360)+",100%,80%)";
    return '  <div style="background-color:'+hsl+'">'+hsl+'</div>'}).join('\n')
  +'</div>').join('\n');
// === populate the page first ... =============================== END =
  
// now, do the action:
cont.onclick=ev=>{
  if (   ev.target.parentNode.classList.contains('projcolorpick')
      && ev.target.tagName=='DIV'){
    [...ev.target.parentNode.children].forEach(c=>c.classList.toggle('selected',c==ev.target));
    ev.target.parentNode.style.backgroundColor=ev.target.textContent;
  }
}
.projcolorpick {border: 2px solid #888}
.selected {border: 2px solid #fff; transform:scale(1.2);}
div {margin:6px; padding:4px}
.projcolorpick div {width:200px; height:20px}
<div id="container"></div>

动作发生在这里:

cont.onclick=ev=>{
      if (   ev.target.parentNode.classList.contains('projcolorpick')
          && ev.target.tagName=='DIV'){
        [...ev.target.parentNode.children].forEach(c=>c.classList.toggle('selected',c==ev.target));
        ev.target.parentNode.style.backgroundColor=ev.target.textContent;
      }
    }

我使用委托 event-attachment 给父 .container div。第一个 if 语句确保只处理对 .projcolorpick>div 元素的点击。

If you want to include more than one generation between them you need to use something like ev.target.closest('.projcolorpick') instead ...

现在,在 if 块内发生了两件事:

  1. ev.target.parentNode.children 中的所有 DOM 元素上使用 toggle(),class“选定”是
    • 已分配或
    • 已删除。
  2. 在单击的 div 中找到的文本作为 background-color 应用到父 .projcolorpick 容器。