我正在通过为自己设置一些练习来练习基本的JS技能。在这一个中,我在div中有一个<a>
列表。练习的目的是将每个<a>
包装在div中。我在这个例子中使用replaceChild
。
奇怪(至少对我而言)该脚本适用于前三个链接,但之后会抛出错误:
未捕获的TypeError:无法读取未定义的属性“parentNode”
我不知道为什么脚本部分有效。谁能看到我在这里做错了什么?这是我正在使用的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
</div>
<script>
var links = document.getElementsByTagName("a");
for (var i=0, ii=links.length; i<ii; i++)
{
var container = document.createElement("div");
links[i].parentNode.replaceChild(container, links[i]);
container.appendChild(links[i]);
}
</script>
</body>
</html>
这是一个在线版本:http://codepen.io/anon/pen/Lpuky
我已经尝试了一些我所知道的调试技术,并阅读了有关此错误消息的信息,但是没有弄清楚这里有什么问题。对我来说似乎很有趣,它适用于6个链接中的3个。
答案 0 :(得分:4)
集合links
为NodeList
,直播。
由于你要替换它们,它们正在从集合中消失,我们对它们的索引不再指向任何东西。
答案 1 :(得分:2)
您在迭代时修改节点列表。使用数组切片方法制作列表的副本:
var linksCopy = Array.prototype.slice.call(links);
for (var i=0; i<linksCopy.length; i++)
{
var container = document.createElement("div");
linksCopy[i].parentNode.replaceChild(container, linksCopy[i]);
container.appendChild(linksCopy[i]);
}
答案 2 :(得分:1)
作为对此的跟进,我经常听到querySelectorAll()
不同之处在于它返回一个静态Nodelist而不是一个数组,所以我认为这可能在这里派上用场,事实确实如此:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
</div>
<script>
var links = document.querySelectorAll("a");
for (var i=0, ii=links.length; i<ii; i++)
{
var container = document.createElement("div");
links[i].parentNode.replaceChild(container, links[i]);
container.appendChild(links[i]);
}
</script>
</body>
</html>
另外,Array.prototype.slice.call(links)
的替代方法是[].slice.call(links)
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
</div>
<script>
var links = document.getElementsByTagName("a");
var linksCopy = [].slice.call(links);
for (var i=0; i<linksCopy.length; i++)
{
var container = document.createElement("div");
linksCopy[i].parentNode.replaceChild(container, linksCopy[i]);
container.appendChild(linksCopy[i]);
}
</script>
</body>
</html>
另一种选择是使用[].forEach.call()
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
</div>
<script>
[].forEach.call(document.querySelectorAll('a'), function(el) {
var container = document.createElement("div");
el.parentNode.replaceChild(container, el);
container.appendChild(el);
});
</script>
</body>
</html>
另一个选择,使用Array.from():
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
<a href="">link</a>
</div>
<script>
var links = document.getElementsByTagName("a");
var linksCopy = Array.from(links);
for (var i=0; i<linksCopy.length; i++)
{
var container = document.createElement("div");
linksCopy[i].parentNode.replaceChild(container, linksCopy[i]);
container.appendChild(linksCopy[i]);
}
</script>
</body>
</html>
答案 3 :(得分:1)
关于您自己的后续答案:如果您的目标只是找到将<a>
包裹在<div>
中的最简单方法,而不是使用createElement
进行练习,{ {1}}或replaceChild
或任何其他方法,就是这样:
appendChild
。
现场演示:http://jsbin.com/jasoho/1/edit?html,output。 <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Demo</title>
<style>
div div {
padding: 10px;
background: #e7e7e7;
margin: 5px;
}
</style>
</head>
<body>
<div>
<a href="#">link</a>
<a href="#">link</a>
<a href="#">link</a>
<a href="#">link</a>
<a href="#">link</a>
<a href="#">link</a>
</div>
<script>
var links = document.querySelectorAll("a");
for (var i=0; i<links.length; i++) {
links[i].outerHTML = '<div>'+links[i].outerHTML+'</div>';
}
</script>
</body>
</html>
方法的另一个优点是它不会更改outerHTML
。因此,您也可以使用nodeList
代替getElementsByTagName
。