javascript动态添加类而不使用内联函数

时间:2018-06-24 04:17:34

标签: javascript

我正在研究一个简单的示例,如果用户单击元素,则其上方的所有元素应具有一个类,而其下方的所有元素均不应对其应用任何类。

这是我的代码:

<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));
}

如果我将其放置为外部函数,可以帮助我解决代码问题吗?

4 个答案:

答案 0 :(得分:2)

addEventListener中的

myFunction(j)将立即执行该函数。仅将其替换为myFunctionmyFunction将获得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%。

Plunker

演示

演示中评论的详细信息

// 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>