有没有一种方法可以将类添加到所有元素

时间:2019-01-12 21:23:50

标签: javascript css addeventlistener

我浏览了各种类似的问题,但是在解决问题上没有任何真正的帮助。有一些Jquery示例,但是都不适用,因为我只想通过普通JavaScript来实现。

问题

我有一个要构建的评级小部件,就像每次单击“ p”元素时一样,eventListener在单击的元素之前和之后的所有p元素上添加“ good”类,并在所有p元素上删除“ good”类被点击后的内容。

我的想法

我试图选择所有“ p”元素,并通过使用for循环在单击的元素之前和之后添加类,并使其保持不变或在其之后移除,来对其进行遍历,但是我在某个地方做错了它仅在单击的元素上添加类,而不在以前的所有元素上添加类。

我的代码

function rating () {
var paragraph = document.getElementsByTagName('p');
for (var i = 0; i < paragraph.length; i++) {
    paragraph[i].addEventListener('click', function(e) {
        e.target.className='good';
        })
      }
    } 

rating();

结果

预期结果是,被单击的元素之前的每个p元素(包括被单击的元素)在单击后都应具有良好的类,而在被单击的元素之后的所有p元素都不应具有类。

实际结果:只有单击的元素具有良好的类。

3 个答案:

答案 0 :(得分:1)

使用Array#forEach,Element#nextElementSiblingElement#previousElementSibling

其背后的一般逻辑是遍历所有先前和下一个兄弟元素。对于每个元素,添加或删除类.good,直到没有更多兄弟姐妹可以处理为止。

const ps = document.querySelectorAll('p');

ps.forEach(p => {
  p.addEventListener("click", function() {
    let next = this.nextElementSibling;
    let prev = this;
    while(prev !== null){
      prev.classList.add("good");
      prev = prev.previousElementSibling;
    }
    while(next !== null){
      next.classList.remove("good");
      next = next.nextElementSibling;
    }
  })

})
p.good {
  background-color: red;
}

p.good::after {
  content: ".good"
}

p {
  background-color: lightgrey;
}
<div id='rating'>
  <p>*</p>
  <p>*</p>
  <p>*</p>
  <p>*</p>
  <p>*</p>
</div>

替代:

使用Array#slice获取上一组和下一组p。

const ps = document.querySelectorAll('p');

ps.forEach((p,i,list) => {
  p.addEventListener("click", function() {
    
    const arr = [...list];
    const previous = arr.slice(0,i+1);
    const next = arr.slice(i+1);
    
    previous.forEach(pre=>{
       pre.classList.add("good");
    })
    
    next.forEach(nex=>{
        nex.classList.remove("good");
    });
  })

})
p.good {
  background-color: red;
}

p.good::after {
  content: ".good"
}

p {
  background-color: lightgrey;
}
<div id='rating'>
  <p>*</p>
  <p>*</p>
  <p>*</p>
  <p>*</p>
  <p>*</p>
</div>

答案 1 :(得分:1)

关键要素是使用Node.compareDocumentPosition()来确定一个元素是在另一个元素之前还是之后:

var paragraphs;

function handleParagraphClick(e) {

  this.classList.add('good');

  paragraphs.forEach((paragraph) => {

    if (paragraph === this) {
      return;
    }

    const bitmask = this.compareDocumentPosition(paragraph);

    if (bitmask & Node.DOCUMENT_POSITION_FOLLOWING) {
      paragraph.classList.remove('good');
    }

    if (bitmask & Node.DOCUMENT_POSITION_PRECEDING) {
      paragraph.classList.add('good');
    }

  });
}

function setup() {

  paragraphs = [...document.getElementsByTagName('p')];

  paragraphs.forEach((paragraph) => {
    paragraph.addEventListener('click', handleParagraphClick);
  });
}

setup();
#rating { display: flex; }
p { font-size: 32px; cursor: default; }
p:hover { background-color: #f0f0f0; }
.good { color: orange; }
<div id='rating'>
  <p>*</p>
  <p>*</p>
  <p>*</p>
  <p>*</p>
  <p>*</p>
</div>`

答案 2 :(得分:1)

function setup() {
  var paragraph = document.querySelectorAll("p");
  for (p of paragraph) {
    p.onclick = (event) => {
      let index = Array.from(paragraph).indexOf(event.target);
      [].forEach.call(paragraph, function(el) {
        el.classList.remove("good");
      });
      for (let i = 0; i <= index; i++) {
        paragraph[i].classList.add("good");
      }

    }
  }
}

//Example case

document.body.innerHTML = `
<div id='rating'>
<p>*</p>
<p>*</p>
<p>*</p>
<p>*</p>
<p>*</p>
</div>`;

setup();