简体   繁体   中英

Javascript for loop appendChild does not append all items

I am moving list elements in a class from one list to another, but I am getting extremely odd behavior.

The relevant Code is found in these functions:

function moveright(){
            console.log("things that are selected");
            selected=document.getElementsByClassName("Selected");
            for (x=0;x<selected.length;x++){
                    console.log(selected.item(x).innerText);
            }
            list=document.getElementById("rightlist");
            console.log("Moving right");
            for (x=0;x<selected.length;x++){
                    list.appendChild(selected.item(x));
                    console.log(selected.item(x).innerText);
            }
            console.log("things that moved right");
            for (x=0;x<list.childElementCount;x++){

                    console.log(list.children.item(x).innerText);
            }
    }

function select(ele,eve){
                if (!(event.shiftKey)){
                        selected=document.getElementsByClassName("Selected");
                        for (x=0;x<selected.length;x++){
                                selected[x].className=selected[x].className.replace(" Selected","");
                        }
                }
                if (ele.className.indexOf(" Selected") == -1) {
                        ele.className=ele.className+" Selected";
                }
        }

An example of a test element:

<li style="user-select:none" onclick="select(this)" path="./this/is/a/path" class="pft-file ext-txt Selected">test2.txt</li>

rightlist and leftlist are just <ul> elements. When I select three items and execute the moveright function this the console output, which corresponds with what happens on the screen:

things that are selected
test1.txt
test2.txt
test3.txt
Moving right
test2.txt
test1.txt
test3.txt
things that moved right
test1.txt
test3.txt

When I do the same experiment with 2 elements, it still leaves one behind. When I call the function a second time, the last element moves to the rightlist. When I call an identical function to move the elements to the leftlist from the rightlist, it works fine. I'm at my wits end on this one.

EDIT So a little bit of a clue as to what is going on, when I make the list longer, it leaves behind every other item, so any items in the 1,3,5 positions are left and the 0,2,4 positions are taken...

Your issue is that document.getElementsByClassName returns a "live list", which means that elements can disappear from the list and appear into it based on changes you make to the DOM.

For example, if you select by class name "foo" , but then remove that class from one of the elements selected, the element gets removed from the list. If you add the "foo" class to an element, that element gets added to the list. Same goes with removing entire elements from the DOM that were in the collection.

So doing such mutations can have surprising effects, especially in a loop. It's basically the same problem of mutating an Array's structure while you're iterating it.

As a fix, use .querySelectorAll to select the elements. This returns a static list of elements, which will be unaffected by changes in the DOM. The elements themselves will see their own changes of course, but the list of elements won't change.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM