22

目的

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

私の方法

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

問題

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

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

つまり、ユーザーが特定のdivにマウスを合わせると、そのdivのスライドアウトアニメーションを実行する必要があるという考え方です。ただし、代わりに、div1(rangeTabAll)にマウスを合わせると、div4(rangeTabThm)のスライドアウトアニメーションがトリガーされます。同じことがdiv2、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];

したがって、問題が発生したとき、(forループの反復を介して)curTabへの参照を変更すると、実際には、以前のすべての無名関数イベントハンドラーの参照も新しいcurTab値に変更されていることがわかりました。イベントハンドラーは常に最後のdivをターゲットにしました。

したがって、私が本当に行う必要があるのは、curTabオブジェクト参照ではなく無名関数イベントハンドラーにcurTab値を渡すことでした。

ので、私は考えました:

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

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

4

4 に答える 4

23

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

ただし、変数宣言をループに移動するだけでは、これは実現しません。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
  }
}

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

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]); 
}
于 2009-07-30T01:03:53.900 に答える
19

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

あなたがする必要があるのはこれを変更することです:

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

これに:

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

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

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

ちょっと複雑ですが、考えてみれば当然のことです。閉鎖は奇妙です。

編集: おっと、内部関数を返すのを忘れていました。修理済み。

于 2009-07-30T01:08:42.360 に答える
1

これを必要以上に複雑にしていると思います。マウスオーバー/アウトにスライド効果を割り当てるだけの場合は、jqueryでホバー効果を試してください。

$("#mytab").hover(function(){
    $(this).next("div").slideDown("fast");},
  function(){
    $(this).next("div").slideUp("fast");
});

完全な HTML を投稿していただければ、その方法を正確にお伝えできます :)

于 2009-07-30T01:00:54.130 に答える
1

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

 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
于 2012-03-26T21:13:39.020 に答える