我正在研究一个简单的示例,如果用户单击元素,则其上方的所有元素应具有一个类,而其下方的所有元素均不应对其应用任何类。
这是我的代码:
<style>
p {
background-color: skyblue;
text-align: center;
color: white;
width: 50px;
height: 50px;
cursor: pointer;
}
.active {
color: red;
background-color: black;
}
</style>
<div id="divid">
<p id="p1">one</p>
<p id="p2">two</p>
<p id="p3">three</p>
<p id="p4">four</p>
</div>
<script>
function myFunction(index) {
for (let i = 0; i <= index; i++) {
paragraphs[i].classList.add('active');
}
for (let i = index; i < paragraphs.length; i++) {
paragraphs[i].classList.remove('active');
}
}
var paragraphs = document.querySelectorAll("p");
console.log(paragraphs);
for(var j=0;j<paragraphs.length; j++) {
paragraphs[j].addEventListener("click", myFunction(j));
}
</script>
当我运行这段代码时,它直接将活动类设置为前3段标记,这不是预期的行为,并且click功能无法正常工作。
如果我将Javascrip代码替换为内联函数,那么它将正常工作。
var paragraphs = document.querySelectorAll("p");
console.log(paragraphs);
for(var j=0;j<paragraphs.length; j++) {
paragraphs[j].addEventListener("click", (function(index) {
return function() {
for (let i = 0; i <= index; i++) {
paragraphs[i].classList.add('active');
}
for (let i = index; i < paragraphs.length; i++) {
paragraphs[i].classList.remove('active');
}
}
})(j));
}
如果我将其放置为外部函数,可以帮助我解决代码问题吗?
答案 0 :(得分:2)
myFunction(j)
将立即执行该函数。仅将其替换为myFunction
。 myFunction
将获得event
对象。从事件对象中,您可以获取目标,这将有助于获取子元素的索引。
您可以调整m
值上的迭代以从所需元素中添加或删除类
function myFunction(index) {
// this will first create an array of all the child elmenets
// then the indexOf will get the index of the child which was clicked
let m = Array.from(index.target.parentNode.children).indexOf(index.target);
for (let i = 0; i < m; i++) {
paragraphs[i].classList.add('active');
}
for (let i = m + 1; i < paragraphs.length; i++) {
paragraphs[i].classList.remove('active');
}
}
var paragraphs = document.querySelectorAll("p");
for (var j = 0; j < paragraphs.length; j++) {
paragraphs[j].addEventListener("click", myFunction);
}
p {
background-color: skyblue;
text-align: center;
color: white;
width: 50px;
height: 50px;
cursor: pointer;
}
.active {
color: red;
background-color: black;
}
<div id="divid">
<p id="p1">one</p>
<p id="p2">two</p>
<p id="p3">three</p>
<p id="p4">four</p>
</div>
答案 1 :(得分:1)
我怀疑您遇到问题的原因是,通常在之前加载所有外部文件才有机会加载。每当有内联函数时,通常都在DOM元素之后 定义它,以便加载元素,这就是为什么您可以选择它们并添加事件侦听器的原因。
尝试在其中包装逻辑:
document.addEventListener("DOMContentLoaded", function(event) {
// Place your code here.
});
或者,如果您使用jQuery,请使用:
$(document).ready(function() {
// Place your code here.
});
这将允许您加载DOM元素,然后再尝试在代码中使用它们,使它们可以在单独的js文件中访问。
答案 2 :(得分:0)
您可以在匿名函数内部调用该函数:
function myFunction(index) {
for (let i = 0; i < index; i++) {
paragraphs[i].classList.add('active');
}
for (let i = index; i < paragraphs.length; i++) {
paragraphs[i].classList.remove('active');
}
}
var paragraphs = document.querySelectorAll("p");
for(let j=0;j<paragraphs.length; j++) {
paragraphs[j].addEventListener("click", function(){
myFunction(j);
});
}
p {
background-color: skyblue;
text-align: center;
color: white;
width: 50px;
height: 50px;
cursor: pointer;
}
.active {
color: red;
background-color: black;
}
<div id="divid">
<p id="p1">one</p>
<p id="p2">two</p>
<p id="p3">three</p>
<p id="p4">four</p>
</div>
答案 3 :(得分:0)
以下内容通过使父div监听其所有后代节点的click事件,来使用 Event Delegation 。现在,任何点击的<p>
将是 event.target
,父div是 event.currentTarget
。这两个事件属性将可靠地引用节点,而无需ID,类,属性或tagName。
将<script>
标记作为外部文件放置在结束</body>
标记之前。它的工作时间为99.9%。
演示中评论的详细信息
// Reference the parent node
var mom = document.querySelector('div');
/* Collect all of mom's paragraphs into a nodeList then turn it into an array.
*/
var kids = Array.from(mom.querySelectorAll('p'));
/* Event Delegation
|| Register the click event to mom
|| Now any click to a kid (e.target) will propagate to mom (e.currentTarget).
|| That's only one event listener for any number of descendant nodes.
*/
mom.addEventListener('click', olderBros);
function olderBros(e) {
// Remove .active from all of the kids
kids.forEach(function(k) {
k.className = "";
});
// Make sure that the clicked node is NOT mom
if (e.target !== e.currentTarget) {
// Reference the clicked node...
var tgt = e.target;
// Assign the clicked node .active class
// Remove this line if you don't want clicked node .active
tgt.className = "active";
var i, j = kids.legnth;
// Add .active to all older/previous <p>/Element Bros/Sibling
for (i = 0; tgt = tgt.previousElementSibling; i++) {
kids[i].classList.add('active');
}
// Remove .active to all younger/next <p>/Element Bros/Sibling
for (let k = (i + 1); k < (j - i); k++) {
kids[k].classList.remove('active');
}
} else {
return false;
}
// Stop event bubbling
e.stopPropagation()
}
<!DOCTYPE html>
<html>
<head>
<style>
p {
background-color: skyblue;
text-align: center;
color: white;
width: 50px;
height: 50px;
cursor: pointer;
}
.active {
color: red;
background-color: black;
}
</style>
</head>
<body>
<div>
<p>one</p>
<p>two</p>
<p>three</p>
<p>four</p>
<p>five</p>
<p>six</p>
<p>seven</p>
<p>eight</p>
<p>nine</p>
<p>ten</p>
<p>eleven</p>
<p>twelve</p>
</div>
<script src="script.js"></script>
</body>
</html>