3

我有一个指向图像的链接列表,以及一个 js 函数,它接受一个(图像的)URL,并在调用该函数时将该图像放在页面上。

我最初是为每个 a 添加一个内联 onlick="showPic(this.getAttribute('href'))" ,但我想分离出内联 js。这是我在页面加载时为每个标签添加 onclick 的函数:

function prepareLinks(){
var links = document.getElementsByTagName('a');
for(var i=0; i<links.length; i++){
    var thisLink = links[i];
    var source = thisLink.getAttribute('href'); 
    if(thisLink.getAttribute('class') == 'imgLink'){
        thisLink.onclick = function(){
            showPic(source);
            return false;
        }
    }
}
}

function showPic(source){
var placeholder = document.getElementById('placeholder');
placeholder.setAttribute('src',source);
}

window.onload = prepareLinks();

...但每次调用 showPic 时,源变量都是最后一张图像的 href。我怎样才能让每个链接都有正确的点击?

4

4 回答 4

4

JavaScript 没有块作用域,因此封闭变量最终是最后分配给它的任何内容。您可以通过将其包装在另一个闭包中来解决此问题:

function prepareLinks() {
    var links = document.getElementsByTagName('a');
    for(var i = 0; i < links.length; i++) {
        var thisLink = links[i];
        var source = thisLink.getAttribute('href'); 
        if(thisLink.getAttribute('class') == 'imgLink') {
            thisLink.onclick = (function(source) {
                return function() {
                    showPic(source);
                    return false;
                };
            })(source);
        }
    }
}

当然,您可以使这个更简单并使用this

function prepareLinks() {
    var links = document.getElementsByTagName('a');

    for(var i = 0; i < links.length; i++) {
        var thisLink = links[i];

        if(thisLink.getAttribute('class') == 'imgLink') {
            thisLink.onclick = function() {
                showPic(this.href);
                return false;
            };
        }
    }
}

我相信这会破坏与 IE5 或 IE6 的兼容性,但希望你不关心其中任何一个 =)

于 2012-04-12T23:25:10.580 回答
2

Minitech 的答案应该可以解决您的问题,即该source变量由您的所有 onclick 处理程序共享

您这样做的方式非常浪费,无需为每个链接设置单独的处理程序。此外,如果动态添加任何链接,它将不起作用。事件委托是要走的路。

function interceptLinks() {
   // Bad way to set onclick (use a library)
   document.onclick = function() {
     if (this.tagName.toUpperCase() != 'A' ) {
       return;
     }
     // Bad way to check if it contains a class (use a library)
     if (this.getAttribute('class') == 'imgLink') {
       showPic(this.getAttribute('href'));
       return false;
     }
   }
}
于 2012-04-12T23:31:49.710 回答
0

Thanks for all the replies. Turns out I had diagnosed the problem incorrectly, sorry. Actually using a new var and annon. function to add an onclick on each loop iteration works (the passed href is correct). It was not working because I was getting at the a-tags by the "imgLink" class which I had removed from the HTML when I removed the inline onclick handlers (I get them with an ID on a parent now). Also I needed to use "return !showPic(this.href);" to stop the link being followed normally when clicked.

Working code:

function showPic(source){
var placeholder = document.getElementById('placeholder');
placeholder.setAttribute('src',source);
return true;
}

function prepareLinks() {
if(!document.getElementById('imgLinks')){ return false; };
var galLinks = document.getElementById('imgLinks');
var links = galLinks.getElementsByTagName('a');
for(var i=0; i<links.length; i++) {
    var thisLink = links[i];
    thisLink.onclick = function() {
        return !showPic(this.href);
    };
}
}

window.onload = function(){
prepareLinks();
}
于 2012-04-13T13:40:32.213 回答
0

这是访问外部变量的循环内部的事件处理程序的古老问题。

您的source变量在事件发生时从范围链中拉出,到那时,由于迭代已完成click,它已被设置为最后一个属性。href

您需要通过做两件事之一来打破封闭。

最简单但不受许多浏览器支持的是使用let它可以让您使用块范围。

let source = thisLink.getAttribute('href'); 

js小提琴。它适用于 Firefox,但不适用于 Chrome。

在 2038 年,当我们处理2038 年问题并且所有浏览器都实现了 ES6 时,这将是解决这个问题的标准方法。

一个更难理解和实现兼容所有浏览器的方法是用一种模式打破闭包,例如......

thisLink.onclick = (function(src) {
  return function(){
            showPic(src);
            return false;
        }
})(source);

js小提琴

于 2012-04-12T23:27:09.387 回答