質問

目的

サイト全体のページの一部のdivにイベントハンドラーを動的に割り当てたい。

マイメソッド

jQueryを使用して、選択したdivイベントのハンドラーとして匿名関数をバインドしています。

問題

このコードは、div名と関連URLの配列を繰り返し処理します。 div名は、バインディングターゲットの設定に使用されます。つまり、このdivイベントにこのイベントハンドラーをアタッチします。

イベントハンドラーは各divイベントに正常にバインドされますが、それらのイベントハンドラーによってトリガーされるアクションは、配列の最後のアイテムのみをターゲットにします。

つまり、ユーザーが特定のdivにマウスを重ねると、そのdivのスライドアウトアニメーションを実行するという考え方です。ただし、代わりに、div1(rangeTabAll)にマウスを合わせると、div4(rangeTabThm)のスライドアウトアニメーションがトリガーされます。 div 2、3などにも同じことが言えます。順序は重要ではありません。周囲の配列要素を変更すると、イベントは常に配列の最後の要素div4をターゲットにします。

マイコード-(jQueryを使用)

var curTab, curDiv;
var inlineRangeNavUrls=[['rangeTabAll','range_all.html'],['rangeTabRem','range_remedial.html'],
                ['rangeTabGym','range_gym.html'],['rangeTabThm','range_thermal.html']];
        for (var i=0;i<inlineRangeNavUrls.length;i++)
        {
            curTab=(inlineRangeNavUrls[i][0]).toString();
            curDiv='#' + curTab;
            if  ($(curDiv).length)
            {
                $(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);} );
                $(curDiv).bind("mouseout", function(){showHideRangeSlidingTabs(curTab, false);} );
            }
        }

私の理論

目もくらむほど明白な構文エラーも、参照による問題もありません。 最初は、curTabの値を設定する次のステートメントがありました。

curTab=inlineRangeNavUrls[i][0];

問題が発生したとき、curTabへの参照を(ループの繰り返しを介して)変更すると、実際には以前のすべての匿名関数イベントハンドラーの参照を新しいcurTabに変更していた値も同様です。これが、イベントハンドラーが常に最後のdivを対象とした理由です。

だから本当に必要なのは、curTab object 参照ではなく、curTab value を匿名関数イベントハンドラに渡すことです。

だから私は考えた:

curTab=(inlineRangeNavUrls[i][0]).toString();

問題は解決しますが、解決しません。同じ取引。したがって、明らかに、いくつかのキー、およびおそらく非常に基本的な問題に関する知識が欠けています。ありがとう。

役に立ちましたか?

解決

ループを通過するたびに新しい変数を作成する必要があります。これにより、イベントハンドラー用に作成しているクロージャーに変数がキャプチャされます。

ただし、変数宣言をループに移動するだけではこれを達成できません。これは、 JavaScriptは、任意のブロックに新しいスコープを導入しません

新しいスコープの導入を強制する簡単な方法の1つは、別の匿名関数を使用することです:

for (var i=0;i<inlineRangeNavUrls.length;i++)
{
  curDiv='#' + inlineRangeNavUrls[i][1];
  if ($(curDiv).length)
  {
    (function(curTab)
    {
      $(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);} );
      $(curDiv).bind("mouseout", function(){showHideRangeSlidingTabs(curTab, false);} );
    })(inlineRangeNavUrls[i][0]); // pass as argument to anonymous function - this will introduce a new scope
  }
}

As Jasonが提案する、jQueryの組み込み を使用して、実際にかなりきれいにすることができます。 hover() 関数:

for (var i=0;i<inlineRangeNavUrls.length;i++)
{
  (function(curTab) // introduce a new scope
  {
  $('#' + inlineRangeNavUrls[i][1])
    .hover(
      function(){showHideRangeSlidingTabs(curTab, true);},
      function(){showHideRangeSlidingTabs(curTab, false);} 
    );
  // establish per-loop variable by passsing as argument to anonymous function
  })(inlineRangeNavUrls[i][0]); 
}

他のヒント

ここで起こっていることは、あなたの匿名関数がクロージャを形成し、それらの外側のスコープをそれらと一緒に持っているということです。つまり、匿名関数内でcurTabを参照する場合、イベントハンドラーがその関数を実行すると、外部スコープでcurTabの current 値が検索されます。これは、curTabに最後に割り当てたものです。 (関数をバインドしたときに割り当てられたものではありません)

これを変更する必要があります:

$(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);} );

これ:

$(curDiv).bind("mouseover", 
    (function (mylocalvariable) { 
        return function(){
            showHideRangeSlidingTabs(mylocalvariable, true);
        } 
    })(curTab) 
);

これにより、curTabの値が外部関数のスコープにコピーされ、内部関数はそれを使用します。このコピーは、内部関数をイベントハンドラーにバインドするのと同時に行われるため、&quot; mylocalvariable&quot;その時点でのcurTabの値を反映します。次に、ループの次回に、新しいスコープを持つ新しい外部関数が作成され、curTabの次の値がそこにコピーされます。

shog9の答えは基本的に同じことを達成しますが、彼のコードはもう少し厳格です。

ちょっと複雑ですが、考えてみると意味があります。閉鎖は奇妙です。

edit:おっと、内部関数を返すのを忘れました。修正。

変数の値を存在しないタグに入れて、後でそこから読み取ることができます。このスニペットはループ本体の一部です:

 s = introduction.introductions[page * 6 + i][0]; //The variables content
 $('#intro_img_'+i).attr('tag' , s);              //Store them in a tag named tag
 $('#intro_img_'+i).click( function() {introduction.selectTemplate(this, $(this).attr('tag'));}  );  //retrieve the stored data
scroll top