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

Posted on   书中枫叶  阅读(104)  评论(0编辑  收藏  举报

背景:

我想在html3个ul中动态生成5个子元素li

目标效果:

image.png

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

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. 失败,没达到预期效果

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

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

image.png

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

image.png

两个问号

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

返回查看代码

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

好,修改成let

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

4. 查阅资料

查阅资料中......

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

MDN官方文档 API:appendChild
MDN官方文档 API:cloneNode

image.png

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

查看效果,成功解决

image.png

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~

相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?

随笔 - 24, 文章 - 0, 评论 - 13, 阅读 - 59526

Copyright © 2025 书中枫叶
Powered by .NET 9.0 on Kubernetes

点击右上角即可分享
微信分享提示