3

画像を指すリンクのリストと、(画像の)URLを取得し、関数が呼び出されたときにその画像をページに配置するjs関数があります。

私はもともとインラインonlick="showPic(this.getAttribute('href'))"を各aに追加していましたが、インライン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になります。各リンクに正しいonclickを設定するにはどうすればよいですか?

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

これは、外部変数にアクセスするループ内のイベントハンドラーの古くからの問題です。

イベントsourceの時点で変数はスコープチェーンから削除され、それまでに、反復が終了したため、変数はclick最後の属性に設定されています。href

あなたは2つのことのうちの1つをすることによって閉鎖を破る必要があります。

最も簡単ですが、多くのブラウザでサポートされていないのは、letブロックスコープを使用できるようにすることです。

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

jsFiddle。Firefoxでは機能しましたが、Chromeでは機能しませんでした。

2038年問題に対処し、すべてのブラウザがES6を実装している場合、これがこの問題を解決するための標準的な方法になります。

すべてのブラウザと互換性のあるメソッドを理解して実装するのがより難しいのは、次のようなパターンでクロージャを壊すことです...

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

jsFiddle

于 2012-04-12T23:27:09.387 に答える
0

すべての返信をありがとう。申し訳ありませんが、問題を誤って診断したことが判明しました。実際に新しいvarとannonを使用しています。ループの反復ごとにonclickを追加する関数が機能します(渡されたhrefは正しいです)。インラインonclickハンドラーを削除したときにHTMLから削除した「imgLink」クラスによってa-tagsを取得していたため、機能しませんでした(現在、親のIDで取得しています)。また、「return!showPic(this.href);」を使用する必要がありました。クリックしたときにリンクが正常にたどられるのを停止します。

作業コード:

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 に答える