我浏览了各种类似的问题,但是在解决问题上没有任何真正的帮助。有一些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元素都不应具有类。
实际结果:只有单击的元素具有良好的类。
答案 0 :(得分:1)
使用Array#forEach,Element#nextElementSibling和Element#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();