XMLHttpRequest加载购物车后appendChild仅显示单个子元素的问题
问题分析与解决方案
嘿,我一眼就发现你遭遇的问题根源啦!你现在只有第一个商品行显示的原因很简单:DOM元素是不能被重复插入到文档中的。
你当前的代码里,每次循环都是直接把同一个sampleBody元素添加到文档片段里——但DOM节点在文档中只能存在一个位置。第一次循环时,你把sampleBody从隐藏表格移到了文档片段;第二次循环再执行html.appendChild(sampleBody),其实是把这个元素从文档片段里“挪”出来再重新放进去,等于一直在修改同一个节点的内容,最后DOM里只会留下最后一次循环修改后的那个节点(也就是倒序的第一个数据项)。
修复方案:克隆DOM节点
解决这个问题的关键是每次循环都克隆一个新的样板行节点,使用cloneNode(true)方法来完成深克隆(会复制节点本身以及所有子元素和属性)。
修改后的JavaScript代码
(function() { 'use strict'; var sampleBody, cartBody; var data = [ { name: "product 1", price: 15, quantity: 2, total: 30 }, { name: "name of product 2", price: 10, quantity: 3, total: 30 } ]; function init() { sampleBody = document.getElementById('sampleBody'); cartBody = document.getElementById('cartBody'); } init(); var renderCart = function(data) { var html = document.createDocumentFragment(); for (var i = data.length; i--;) { // 深克隆样板行,生成新的DOM节点 var row = sampleBody.cloneNode(true); // 使用新克隆的节点来填充数据 row.querySelector('#name').innerText = data[i].name; row.querySelector('#price').innerText = data[i].price; row.querySelector('#quantity').value = data[i].quantity; row.querySelector('#total').innerText = data[i].total; html.appendChild(row); } while (cartBody.firstChild) { cartBody.removeChild(cartBody.firstChild); } cartBody.appendChild(html); }; renderCart(data); })();
额外优化:避免重复ID问题
另外还有个小问题需要注意:你样板行里的id="name"、id="price"这些属性,在克隆后会在页面中出现多个相同ID的元素,这违反了HTML规范(ID必须唯一)。建议把这些ID改成class,避免冲突:
修改后的HTML样板行
<table class="hidden"> <tr id="sampleBody"> <td class="name"></td> <td>€<span class="price"></span></td> <td> <button>+</button> <input type="text" class="quantity"> <button>-</button> </td> <td>€<span class="total"></span></td> </tr> </table>
对应修改JavaScript中的选择器
row.querySelector('.name').innerText = data[i].name; row.querySelector('.price').innerText = data[i].price; row.querySelector('.quantity').value = data[i].quantity; row.querySelector('.total').innerText = data[i].total;
这样修改后,所有商品行就能正常显示,同时也符合HTML规范啦!
内容的提问来源于stack exchange,提问作者H. Pauwelyn
相关产品推荐
相关产品推荐

