className only changing every other class

2020-02-11 17:18发布

I'm performing a small text with JavaScript with the getElementsByClassName() and I am getting some unwanted results. I would like the script to change each CSS class to a new class. The issue is that every other class is only changing...

I would like to use pure js how this issue as it is for practice purposes.

The first thing that came to mind was white spaces, although when removing the this did not make any differnce.

Can anyone point our what I am doing wrong?

<html>
    <head>
       <link rel="stylesheet" type="text/css" href="default.css">
    </head>
    <body>
        <div class="block-default">BLOCK1</div>
        <div class="block-default">BLOCK2</div>
        <div class="block-default">BLOCK3</div>
        <div class="block-default">BLOCK4</div>
        <div class="block-default">BLOCK5</div>
        <div class="block-default">BLOCK6</div>
        <div class="block-default">BLOCK7</div>
        <div class="block-default">BLOCK8</div>
        <script>

    var blockSet = document.getElementsByClassName("block-default");
    var blockSetLength = blockSet.length;

    blockSet[0].className = "block-selected";
    blockSet[1].className = "block-selected";
    blockSet[2].className = "block-selected";
    blockSet[3].className = "block-selected";
    blockSet[4].className = "block-selected";
    blockSet[5].className = "block-selected";
    blockSet[6].className = "block-selected";
    blockSet[7].className = "block-selected";   

        </script>
    </body>
</html>

CSS Classes:

.block-default {
    width: 100px;
    height:50px;
    background-color: green;
    border: 1px solid red;
    padding:10px;
}

.block-selected {
    width: 100px;
    height:50px;
    background-color: blue;
    border: 1px solid white;
    padding:10px;
 }

15条回答
狗以群分
2楼-- · 2020-02-11 17:52

First, the below code should do the trick in the simplest way.

var blockSet = document.getElementsByClassName("block-default").className = "block-selected";

Next what goes wrong with your code, or rather what is the interesting thing that is happening:

blockSet[0].className = 'block-selected';

makes the first block set element no longer a block set element. That leaves you with 7 remaining. Now,

blockSet[1].className = 'block-selected';

Selects the second one of the remaining ones. Which would be the third one of your complete list. Now you have 6 remaining.

blockSet[2].className = 'block-selected';

This makes the third one among the remaining, which would be your BLOCK5 into a block selected. And results in you having 5 remaining.

blockSet[3].className = 'block-selected'; 

This again finds your fourth one which is BLOCK7 when you count to the fourth among your remaining. And now you have 4 remaining.

blockSet[4] onwards find no such element and fail to execute. This is what happens with your code. Quite interesting. :).

Here is a jsfiddle alerting you the values as they run: https://jsfiddle.net/xz7h57jv/

查看更多
啃猪蹄的小仙女
3楼-- · 2020-02-11 17:55

Because you change the .className of the blockSet which is an HTMLCollection. The collection that have elements with same class (block-default) will change when the elements suffers some updates.

In other words when you change the .className of an element the collection will exclude that element. This means that the size of the HTMLCollection will decrease . Also the size will increase if an element with that class has beed added to the DOM.

To solve this you can always change only the first element .className.

for(var i = 0; i<blockSetLength; i++)
{
    blockSet[0].className = "block-selected";
}

Notes: Intead of changing class element by element, you can iterate through elements with for and change .className.

var blockSet = document.getElementsByClassName("block-default");
var blockSetLength = blockSet.length;

console.log(blockSet);

for(var i = 0; i<blockSetLength; i++)
{
    blockSet[0].className = "block-selected";
}
.block-default {
    width: 100px;
    height:50px;
    background-color: green;
    border: 1px solid red;
    padding:10px;
}

.block-selected {
    width: 100px;
    height:50px;
    background-color: blue;
    border: 1px solid white;
    padding:10px;
 }
<div class="block-default">BLOCK1</div>
<div class="block-default">BLOCK2</div>
<div class="block-default">BLOCK3</div>
<div class="block-default">BLOCK4</div>
<div class="block-default">BLOCK5</div>
<div class="block-default">BLOCK6</div>
<div class="block-default">BLOCK7</div>
<div class="block-default">BLOCK8</div>

If you add a new item in DOM (not collection) the size will increase as presented in the example below.

var blockSet = document.getElementsByClassName("block-default");
var blockSetLength = blockSet.length;

alert("Current size: " + blockSet.length);
document.body.innerHTML += '<div class="block-default">BLOCK9</div>';
alert("After adding an element in DOM size: " + blockSet.length);
.block-default {
    width: 100px;
    height:50px;
    background-color: green;
    border: 1px solid red;
    padding:10px;
}

.block-selected {
    width: 100px;
    height:50px;
    background-color: blue;
    border: 1px solid white;
    padding:10px;
 }
<div class="block-default">BLOCK1</div>
<div class="block-default">BLOCK2</div>
<div class="block-default">BLOCK3</div>
<div class="block-default">BLOCK4</div>
<div class="block-default">BLOCK5</div>
<div class="block-default">BLOCK6</div>
<div class="block-default">BLOCK7</div>
<div class="block-default">BLOCK8</div>

查看更多
干净又极端
4楼-- · 2020-02-11 17:56

This error occurs because blockSet is an HTMLCollection, which is "live." HTMLCollections update as the elements on the page update.

Every time you swap a className, you're making blockSet shorter one by one.

To solve this problem, just do this instead:

for (var i = 0; i < 8; i += 1) {
    blockSet[ 0 ].className = "block-selected";
}

That way you chunk your HTMLCollection off one by one.

Iteration 1: [ div1, div2, div3, div4, div5, div6, div7, div8 ]

Iteration 2: [ div2, div3, div4, div5, div6, div7, div8 ]

Iteration 3: [ div3, div4, div5, div6, div7, div8 ]

Iteration 4: [ div4, div5, div6, div7, div8 ]

Iteration 5: [ div5, div6, div7, div8 ]

Iteration 6: [ div6, div7, div8 ]

Iteration 7: [ div7, div8 ]

Iteration 8: [ div8 ]

Hope that helps!

查看更多
我命由我不由天
5楼-- · 2020-02-11 17:58

Use this to your javascript code. this will fix your error

<script>
    var blockSet = document.getElementsByClassName("block-default");
    var blockSetLength = blockSet.length;

    for (var i = blockSet.length - 1; i >= 0; i--) {
        blockSet[i].className = "block-selected";
    };
</script>
查看更多
爷、活的狠高调
6楼-- · 2020-02-11 17:59

This worked for me

var blockSet = document.getElementsByClassName("block-default");
    var blockSetLength = blockSet.length;
 blockSet[0].className = "block-selected";
 blockSet[0].className = "block-selected";
 blockSet[0].className = "block-selected";
 blockSet[0].className = "block-selected";
 blockSet[0].className = "block-selected";
 blockSet[0].className = "block-selected";
 blockSet[0].className = "block-selected";
 blockSet[0].className = "block-selected";

   
.block-default {
    width: 100px;
    height:50px;
    background-color: green;
    border: 1px solid red;
    padding:10px;
}

.block-selected {
    width: 100px;
    height:50px;
    background-color: blue;
    border: 1px solid white;
    padding:10px;
 }
<div class ="block-default">BLOCK1</div>
<div class ="block-default">BLOCK2</div>
<div class ="block-default">BLOCK3</div>
<div class ="block-default">BLOCK4</div>
<div class ="block-default">BLOCK5</div>
<div class ="block-default">BLOCK6</div>
<div class ="block-default">BLOCK7</div>
<div class ="block-default">BLOCK8</div>

查看更多
叼着烟拽天下
7楼-- · 2020-02-11 18:01

You can find the working code over here

<div class="block-default">BLOCK1</div>
<div class="block-default">BLOCK2</div>
<div class="block-default">BLOCK3</div>
<div class="block-default">BLOCK4</div>
<div class="block-default">BLOCK5</div>
<div class="block-default">BLOCK6</div>
<div class="block-default">BLOCK7</div>
<div class="block-default">BLOCK8</div>


var blockSet = document.getElementsByClassName("block-default");
var blockSetLength = blockSet.length;

for (i = 0; i < blockSetLength; i++) {
    blockSet[0].className = "block-selected";
}

Demo link http://jsfiddle.net/patelmit69/9koxfaLq/1/

查看更多
登录 后发表回答