0

我正在通过为自己设置一些小练习来练习基本的 JS 技能。在这个中,我<a>在 div 中有一个 s 列表。练习的目的是将每个都包装<a>在一个 div 中。我replaceChild在这种情况下使用。

奇怪的是(至少对我而言)该脚本适用于前三个链接,但之后会引发错误:

未捕获的类型错误:无法读取未定义的属性“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 个。

4

4 回答 4

4

该系列linksNodeList并且是现场的。

由于您要替换它们,它们将从集合中消失,我们对它们的索引不再指向任何东西。

于 2013-05-08T04:02:53.627 回答
2

您在迭代节点列表时正在修改它。使用 Array 切片方法制作列表的副本:

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]);
}
于 2013-05-08T04:05:03.523 回答
1

作为对此的跟进,我经常听到它querySelectorAll()的不同之处在于它返回一个静态节点列表而不是一个数组,所以我认为这在这里可能会派上用场,而且确实如此:

<!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>
于 2013-12-06T05:32:25.300 回答
1

关于您自己的后续答案:如果您的目标只是找到将 s 包装在<a>s 中的最简单方法<div>,而不是使用createElementreplaceChildappendChild任何其他方法进行练习,那就是:

<!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>

.
现场演示:http: //jsbin.com/jasoho/1/edit ?html,output 。该方法的另一个优点outerHTML是它不会更改nodeList. 所以你也可以getElementsByTagNamequerySelectorAll.

于 2014-07-10T13:07:08.930 回答