JS的for循环动态渲染html只有最后一个元素生效?

lxf2023-05-05 08:14:01

背景:

我想在html3个ul中动态生成5个子元素li 但是只有第三个ul渲染出子元素,其他两没有?

目标效果:

JS的for循环动态渲染html只有最后一个元素生效?

废话少说,代码直接梭起来~

1. 先写html结构

<section class="list-box">
    <ul id="myList"></ul>
    <ul id="myListOne"></ul>
    <ul id="myListTwo"></ul>
</section>

2. 动态渲染子元素li

不就是写个for循环呗,并且我还加了class属性item

for (var i = 1; i <= 5; i++) {
        var listItem = document.createElement("li");
        listItem.setAttribute('class', 'item')
        document.getElementById("myList").appendChild(listItem);
        document.getElementById("myListOne").appendChild(listItem);
        document.getElementById("myListTwo").appendChild(listItem);
    }

3. 失败,没达到预期效果

心想这个简单,很自信的打开浏览器查阅效果

哦豁?怎么回事?只有一列?

JS的for循环动态渲染html只有最后一个元素生效?

不应该呢,赶紧F12打开控制台查看

JS的for循环动态渲染html只有最后一个元素生效?

两个问号

  1. myListmyListOne 怎么没有渲染出子元素li呢?
  2. 为什么只有myListTwo渲染出来子元素?

返回查看代码

难道是 var定义变量的问题么?

好,修改成let

还是一样只有一列,有点迷了~

4. 查阅资料

查阅资料中......

嘿!好家伙 还真的找到了,开心!

MDN官方文档 API:appendChild

MDN官方文档 API:cloneNode

JS的for循环动态渲染html只有最后一个元素生效?

5. 分析原因

在每次迭代时,listItem都会被添加到myListmyListOnemyListTwo中。但是,由于 DOM (文档对象模型) 的规则限制,一个 DOM 元素节点在同一时刻只能存在于 DOM 树的一个位置。 也就是说,在每次循环迭代时,都需要创建新的li元素节点,而不是重复使用同一个listItem。因此,当listItem被添加到myListTwo之后,它就从myListmyListOne中被移除了,因为它已经成为了myListTwo的子元素。

6. 解决问题

两个解决办法: (1). 用Node.cloneNode()api进行克隆一份副本,每个节点进行单独appendChild()

    for (let i = 1; i <= 5; i++) {
        let listItem = document.createElement("li");
        listItem.setAttribute('class', 'item')
        document.getElementById("myList").appendChild(listItem);
        
        let listItemOne = listItem.cloneNode(true); //true 深度克隆 li下面所有子节点
        listItemOne.setAttribute('class', 'item')
        document.getElementById("myListOne").appendChild(listItemOne);

        let listItemTwo = listItem.cloneNode(true);
        listItemTwo.setAttribute('class', 'item')
        document.getElementById("myListTwo").appendChild(listItemTwo);
    }

(2). 可以通过将listItem = document.createElement("li"),每个节点进行单独appendChild()

    for (let i = 1; i <= 5; i++) {
        let listItem = document.createElement("li");
        listItem.setAttribute('class', 'item')
        document.getElementById("myList").appendChild(listItem);


        let listItemOne = document.createElement("li");
        listItemOne.setAttribute('class', 'item')
        document.getElementById("myListOne").appendChild(listItemOne);

        let listItemTwo = document.createElement("li");
        listItemTwo.setAttribute('class', 'item')
        document.getElementById("myListTwo").appendChild(listItemTwo);
    }

查看效果,成功解决

JS的for循环动态渲染html只有最后一个元素生效?

7. 优化代码

上面两种解决办法都存在相同的代码,抽离出来

    // 定义一个创建并设置属性的函数
    function createListItem(className) {
        let listItem = document.createElement("li");
        listItem.setAttribute('class', className);
        return listItem;
    }

    // 在循环中调用函数创建并添加 <li> 元素
    for (let i = 1; i <= 5; i++) {
        let listItem = createListItem('item');
        document.getElementById("myList").appendChild(listItem);

        let listItemOne = createListItem('item');
        document.getElementById("myListOne").appendChild(listItemOne);

        let listItemTwo = createListItem('item');
        document.getElementById("myListTwo").appendChild(listItemTwo);
    }

溜了~

继续写BUG~