Jak przekazać zmienną według wartości do anonimowej funkcji javascript?

Cel

Chcę dynamicznie przypisywać procedury obsługi zdarzeń do niektórych div na stronach w całej witrynie.

Moja Metoda

Używam jQuery do wiązania funkcji anonimowych jako programów obsługi wybranych zdarzeń div.

Problem

Kod iteruje tablicę nazw div I powiązanych adresów URL. Nazwa div jest używana do Ustawienia wiążącego celu, tzn. dołączenie tej obsługi zdarzenia do tego zdarzenia div.

Podczas gdy procedury obsługi zdarzeń są z powodzeniem powiązane z każdym ze zdarzeń div, akcje wywołane przez te procedury obsługi zdarzeń są skierowane tylko do ostatniej pozycji w tablicy.

Więc chodzi o to, że jeśli użytkownik myszy nad danym div, powinien uruchomić animację slajdów dla tego div. Ale zamiast tego, mousing nad div1 (rangeTabAll) uruchamia animację slide-out dla div4 (rangeTabThm). To samo dotyczy Div 2, 3 itd. Rozkaz jest nieważny. Zmień elementy tablicy, a zdarzenia będą zawsze skierowane na ostatni element w tablicy div4.

Mój kod - (używa 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);} );
            }
        }

Moja Teoria

Albo nie widzę ślepo oczywistego błędu składni, albo jest to problem pass by reference. Początkowo miałem następujące polecenie, aby ustawić wartość curTab:

curTab=inlineRangeNavUrls[i][0];

Więc kiedy pojawił się problem, pomyślałem, że zmieniając (poprzez iterację pętli for) odniesienie do curTab, zmieniłem odniesienie do wszystkich poprzednich procedur obsługi zdarzeń funkcji anonimowych do nowej wartości curTab.... dlatego obsługa zdarzeń zawsze celowała w ostatni div.

Więc to, co naprawdę musiałem zrobić, to przekazać wartość curTab do anonimowych procedur obsługi zdarzeń funkcji, a nie odniesienie do obiektu curTab .

Więc pomyślałem:

curTab=(inlineRangeNavUrls[i][0]).toString();
Rozwiązałoby problem, ale tak nie jest. Więc najwyraźniej brakuje mi jakiejś kluczowej i prawdopodobnie bardzo podstawowej wiedzy dotyczącej problemu. Dzięki.
Author: rism, 2009-07-30

4 answers

Musisz utworzyć nową zmienną przy każdym przejściu przez pętlę, aby została przechwycona w zamknięciach, które tworzysz dla procedur obsługi zdarzeń.

Jednak samo przeniesienie deklaracji zmiennej do pętli tego nie osiągnie, ponieważ JavaScript nie wprowadza nowego zakresu dla dowolnych bloków .

Jednym z łatwych sposobów na wymuszenie wprowadzenia nowego zakresu jest użycie innej anonimowej funkcji:

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
  }
}

Jak sugeruje Jason , możesz właściwie posprzątaj to trochę używając wbudowanego jQueryhover() Funkcja:

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]); 
}
 22
Author: Shog9,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:00

Chodzi o to, że Twoje anonimowe funkcje tworzą zamknięcie i zabierają ze sobą ich zewnętrzny zasięg. Oznacza to, że gdy odwołasz się do curTab wewnątrz swojej funkcji anomymous, kiedy obsługa zdarzeń uruchomi tę funkcję, będzie sprawdzać bieżącą wartość curTab w zewnętrznym zakresie. To będzie to, co ostatnio przypisałeś curtabowi. (nie to, co zostało przypisane w czasie wiązania funkcji)

To, co musisz zrobić, to zmienić to:

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

Do tego:

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

To skopiuje wartość curTab do zakresu funkcji zewnętrznej, którą funkcja wewnętrzna zabierze ze sobą. To kopiowanie dzieje się w tym samym czasie, gdy przypisujesz wewnętrzną funkcję do obsługi zdarzeń, więc "mylocalvariable" odzwierciedla wartość curTab w tym czasie. Następnie następnym razem wokół pętli zostanie utworzona nowa zewnętrzna funkcja z nowym zakresem i skopiowana do niej Następna wartość curTab.

Odpowiedź Shog9 osiąga w zasadzie to samo, ale jego kod jest trochę bardziej surowy.

To trochę skomplikowane, ale ma sens, jeśli się nad tym zastanowić. Zamknięcia są dziwne.

Edit: UPS, zapomniałem zwrócić wewnętrzną funkcję. Naprawione.

 16
Author: Breton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-30 01:20:47

Myślę, że komplikujesz to bardziej, niż musi być. Jeśli wszystko, co robisz, to przypisywanie efektu przesuwania na mouseover / out, spróbuj użyć efektu hover z jquery.

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

Jeśli zamieściłeś swój pełny HTML, mogę ci dokładnie powiedzieć, jak to zrobić:)

 1
Author: Jason,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-30 01:22:39

Możesz umieścić wartość zmiennej w nieistniejącym znaczniku, a później możesz je stamtąd odczytać. Ten fragment jest częścią ciała pętli:

 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
 1
Author: Gyuri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-26 21:13:39