我有一个简单的html菜单:
<div id="menulinks">
<ul>
<li><a href="#link1">Link 1</a></li>
<li><a href="#link2">Link 2</a></li>
<li><a href="#link3">Link 3</a></li>
<li><a href="#link4">Link 4</a></li>
</ul>
</div>
我需要编写一个javascript - 不能使用jQuery - 这给了我一个点击锚链接的href。这就是我所做的:
var a = document.getElementById("menulinks").getElementsByTagName("a");
for ( var o = 0; o < a.length; o++ ) {
var clickedLink = a[o];
clickedLink.addEventListener("click", function() {
var b = clickedLink.getAttribute("href");
alert(b);
});
}
它有效,但无论我点击哪个链接,我总是在警告框中输入'#link4'作为答案。你能告诉我,有什么不对吗?提前谢谢!
答案 0 :(得分:1)
您可以在处理程序中使用this
访问与事件相关的元素。否则,您将引用分配给clickedLink
此外,您可以使用querySelectorAll
快速选择链接。但是,如果链接更改querySelectorAll
返回的列表不会更改,那么您必须再次选择链接。 querySelectorAll
返回NodeList,而不是HTMLCollection,因此无法使用forEach
之类的数组方法进行访问,但在这种情况下它将完美运行。
var a = document.querySelectorAll("#menulinks a");
for (var o = 0; o < a.length; o++) {
a[o].addEventListener('click', function () {
alert(this.href);
}, false);
}
&#13;
<div id="menulinks">
<ul>
<li><a href="#link1">Link 1</a>
</li>
<li><a href="#link2">Link 2</a>
</li>
<li><a href="#link3">Link 3</a>
</li>
<li><a href="#link4">Link 4</a>
</li>
</ul>
</div>
&#13;
答案 1 :(得分:1)
您的问题是每次clickedLink
迭代时for loop
都会被后续值覆盖,当点击链接时,clickedLink
已被分配了最后一个href
1}}值。
我猜测你的混淆是因为假设Javascript在实际使用lexical scoping时有阻止作用域。 (您也可以阅读variable hoisting ...)
一种解决方案是将分配给clickedLink
的每个值绑定到立即调用的函数...
for ( var o = 0; o < a.length; o++ ) {
var clickedLink = a[o];
(function(clickedLink) {
clickedLink.addEventListener("click", function() {
var b = clickedLink.getAttribute("href");
alert(b);
});
})(clickedLink);
}
答案 2 :(得分:1)
这是围绕范围问题的另一种方式;将环体包裹在IIFE中。它基本上是@sfletche的答案,但“向上”一个级别,并且不需要参数:
var a = document.getElementById("menulinks").getElementsByTagName("a");
for (var o = 0; o < a.length; o++) {
(function() {
var clickedLink = a[o];
clickedLink.addEventListener("click", function() {
var b = clickedLink.getAttribute("href");
alert(b);
});
})();
}
<div id="menulinks">
<ul>
<li><a href="#link1">Link 1</a></li>
<li><a href="#link2">Link 2</a></li>
<li><a href="#link3">Link 3</a></li>
<li><a href="#link4">Link 4</a></li>
</ul>
</div>
我不会以这种方式做,但如果您刚刚进入闭包和/或IIFE,它可能更容易理解。
答案 3 :(得分:0)
链接clickedLink
指的是每次迭代都会被覆盖,当链接被点击时,它指的是最后一个链接。
您只需更改
即可轻松解决问题var b = clickedLink.getAttribute("href");
到
var b = this.getAttribute("href");
那么它会起作用:
var a = document.getElementById("menulinks").getElementsByTagName("a");
for ( var o = 0; o < a.length; o++ ) {
var clickedLink = a[o];
clickedLink.addEventListener("click", function() {
var b = this.getAttribute("href");
alert(b);
});
}
<div id="menulinks">
<ul>
<li><a href="#link1">Link 1</a></li>
<li><a href="#link2">Link 2</a></li>
<li><a href="#link3">Link 3</a></li>
<li><a href="#link4">Link 4</a></li>
</ul>
</div>
或者如果你想使用新的ES6功能(在某些现代浏览器中工作但不是全部),那么你可以这样做:
<div id="menulinks">
<ul>
<li><a href="#link1">Link 1</a></li>
<li><a href="#link2">Link 2</a></li>
<li><a href="#link3">Link 3</a></li>
<li><a href="#link4">Link 4</a></li>
</ul>
</div>
<script type="application/javascript;version=1.7">
var a = document.getElementById("menulinks").getElementsByTagName("a");
for ( var o = 0; o < a.length; o++ ) {
let clickedLink = a[o];
clickedLink.addEventListener("click", function() {
alert( clickedLink.getAttribute("href") );
});
}
</script>
答案 4 :(得分:0)
您刚刚发现variable hoisting。这是解释器认为代码的样子。
var a = document.getElementById("menulinks").getElementsByTagName("a");
var clikedLink, o;
for ( o = 0; o < a.length; o++ ) {
clickedLink = a[o];
clickedLink.addEventListener("click", function() {
var b = clickedLink.getAttribute("href");
alert(b);
});
}
由于事件监听器中的clickedLink
为closed over,因此它将在循环的每个交互中继续被覆盖,因此为什么每个链接都给出了最后一个a
标记的href,因为 是最后一个a
标记。
这是你如何正确地做到这一点
var a = document.getElementById("menulinks").getElementsByTagName("a");
for ( var o = 0; o < a.length; o++ ) {
a[o].addEventListener("click", function() {
var b = this.getAttribute("href");
alert(b);
}.bind(a[o]));
}
或者如果你不能使用Function.prototype.bind
:
var a = document.getElementById("menulinks").getElementsByTagName("a");
for ( var o = 0; o < a.length; o++ ) {
(function(l) {
l.addEventListener("click", function() {
var b = l.getAttribute("href");
alert(b);
})(a[o]);
}