2

1年前に大学のクラスでいくつかの基本を学んだ後、Javascriptを独学で学び始めたところです。私が書くことになっているWebアプリの場合、できればクリックして、ユーザーがテーブルの行を「選択」できるようにする必要があります。私には強力な Python のバックグラウンドがあり、私のアプローチはおそらく GTK パラダイムの悪臭を放っています。もっと標準的な方法や受け入れられている方法があるのに、これをやろうとすることで、どういうわけか「車輪の再発明」をしているのではないかとしつこく恐れていますが、私が言ったように、Javascript はまだあまり知りません。これを試すための私のJavascriptコードは次のとおりです。

//Get list of rows in the table
var table = document.getElementById("toppings");
var rows = table.getElementsByTagName("tr");

var selectedRow;

//Row callback; reset the previously selected row and select the new one
function SelectRow(row) {
    if (selectedRow !== undefined) {
        selectedRow.style.background = "#d8da3d";
    }
    selectedRow = row;
    selectedRow.style.background = "white";
}

//Attach this callback to all rows
for (var i = 0; i < rows.length; i++) {
    var idx = i;
    rows[idx].addEventListener("click", function(){SelectRow(rows[idx])});
}

ループが終了した後、idx は rows.length - 1 に等しいため、これは明らかに機能しません。したがって、SelectRow の行引数は、常に最後の行である [rows.length - 1] になります。つまり、i の値は、イベント リスナー コールバックへの引数として「保存」されません。独自の保存された引数を使用してイベント リスナーを呼び出すにはどうすればよいですか? このスレッドは、onclick プロパティを使用してこれを行う方法を提供しているようですが、これは非推奨であり、addEventListener (または巨大な IE 互換の addEvent ライブラリ) が「正しい」方法であることを理解しています。

4

2 に答える 2

2

閉鎖に問題があります。参照は次のとおりです。ループ内の JavaScript クロージャー – 簡単な実用例

これを試して:

for (var i = 0; i < rows.length; i++) {
    (function (idx) {
        rows[idx].addEventListener("click", function() {
            SelectRow(rows[idx]);
        });
    })(i);
}

http://jsfiddle.net/2Vs5w/2/

もちろん、実際に to に渡す必要はありません。渡すrows[idx]ことSelectRowができ、その時点でthisの値を取得するためのクロージャの作成に対処する必要はありません。iだから、このようなもの:

for (var i = 0; i < rows.length; i++) {
    rows[idx].addEventListener("click", function() {
        SelectRow(this);
    });
}

http://jsfiddle.net/2Vs5w/3/

例では、イベントを要素に効果的にアタッチするための関数を含めました。

function addEvent(element, evt, callback) {
    if (element.addEventListener) {
        element.addEventListener(evt, callback, false);
    } else if (element.attachEvent) {
        element.attachEvent("on" + evt, callback);
    } else {
        element["on" + evt] = callback;
    }
}

最新の標準を使用addEventListenerしようとし、次に IE の方法を使用しようとしattachEvent、次に DOM0の方法を使用しようとしますelement.onevent。この関数を取得する場所はいくつかあり、おそらくさらに優れたバージョンもありますが、これは今のところ機能するはずです:)

于 2013-03-22T13:58:24.983 に答える
1

あなたはいつものJavaScriptの落とし穴を見つけました!:)

  1. 変数には関数スコープがあります
  2. クロージャは、(変数値のコピーではなく)親スコープへの参照を維持します。

1 + 2を合計すると、この行が間違っている理由がわかります。

   rows[idx].addEventListener("click", function(){SelectRow(rows[idx])});

idxクロージャー内は親スコープ(2)への参照ですが、ループの最後にあるのはなぜidx = rows.lengthですか?ループの内側に置くことは問題ではありませんvar。宣言は関数レベル(1)にあります。

@Ianソリューションを使用してidxをコピーできます。

注1:イベントハンドラーはイベントオブジェクトを受け取ります。これを使用event.targetして、イベントを発生させたオブジェクトを取得できます。これにより、渡す必要がなくなりますrow[idx]

   rows[idx].addEventListener("click", function(evt){SelectRow(evt.target)});

注2:通常、各行にイベントハンドラーをアタッチすると非効率になる可能性があります。代わりに、イベントハンドラーをテーブルにアタッチしてみてください

于 2013-03-22T14:02:14.867 に答える