我的代码应该在所有具有预定义类名的div中插入HTML内容,而不使用jQuery并且至少与IE8兼容(所以没有getElementsbyClass)。
html:
<div class="target">1</div>
<div class="target">2</div>
<div class="target">3</div>
<div class="target">4</div>
javascript:
var elems = document.getElementsByTagName('*'), i;
for (wwi in elems) {
if((' ' + elems[wwi].className + ' ').indexOf(' ' + "target" + ' ') > -1) {
elems[wwi].innerHTML = "YES";
//elems[wwi].innerHTML = "<div>YES!</div>";
}
}
你可以尝试here。
正如您在每个div中看到的那样,会打印出“是”字样。好吧,如果你评论elems[wwi].innerHTML = "YES";
并将其替换为elems[wwi].innerHTML = "<div>YES!</div>"
,代码就会失败。我想是因为插入div元素会修改DOM,结果FOR循环失败。我是对的吗?
我可以通过在每次创建innerHTML时调用for循环来解决这个问题,当我插入代码时,我可以添加一个类(如data-codeAlreadyInserted = 1)来忽略下次FOR传递那个div。但同样,这是一个非常糟糕的解决方案,因为对于包含许多标签的普通网站,我甚至可以冻结用户浏览器。
你怎么看?假设我不知道我在每个innerHTML调用中插入的标记数量。答案 0 :(得分:1)
“我想是因为插入div元素会修改DOM,结果FOR循环失败。我是对的吗?”
差不多。您的elems
列表是一个在DOM更改时更新的实时列表。因为你在每次迭代时都添加了一个新的div,所以列表不断增长,所以你永远不会结束。
为避免这种情况,您可以进行反向迭代,
for (var i = elems.length-1; i > -1; i--) {
// your code
}
或将列表转换为数组。
var arr = [];
for (var i = 0, len = list.length; i < len; i++) {
arr.push(elems[i]);
}
for (i = 0; i < len; i++) {
// your code
}
答案 1 :(得分:0)
您可以获取实时节点列表的副本:
var nodes = [];
for (var i = 0, n = elems.length; i < n; ++i) {
nodes.push(elems[i]);
}
然后使用正确的for
循环,而不是for ... in
迭代数组:
for (var i = 0, n = nodes.length; i < n; ++i) {
...
}
for ... in
仅应该用于对象,而不是数组。
答案 2 :(得分:0)
另一种方法是使用replaceChild而不是innerHTML。它效果更好,而且速度更快:
var newEl = elem[wwi].cloneNode(false);
newEl.innerHTML = html;
elem[wwi].parentNode.replaceChild(newEl, elem[wwi]);