Jak mądrze dodawać zdarzenia JavaScript

Opublikowano 1.7.2010  w JavaScript » 10 komentarzy
Jak mądrze dodawać zdarzenia JavaScript

Obecnie wszystkie przeglądarki z powodzeniem obsługują typowe zdarzenia JavaScript. Nie znaczy to jednak, że możemy umieszczać je w kodzie naszej strony jakkolwiek chcemy.  Dalej bowiem roboty wyszukiwarek analizują strony pomijając wszelkie skrypty. Nieprawidłowe podpinanie zdarzeń może także źle wpłynąć na odbiór aplikacji przez internautę. Jak uniknąć zatem problemów? O tym właśnie będzie ten poradnik.

Przykład na linkach

Do najczęściej używanych zdarzeń JavaScript należą onClick, onMouseOver i onMouseOut. Najprościej dodać je w ten sposób:

<a href="podstrona.html" onclick="jakas_funkcja(); return false">Kliknij</a>

W takim przypadku mamy wywołanie funkcji, za pomocą return false; blokujemy działanie linka a także w razie braku obsługi JS jesteśmy asekurowani przez odnośnik do pliku podstrona.html. Fajnie, ale IE7 strzeli nam focha. Poza tym nie jest to zbyt eleganckie rozwiązanie. Jak zaczniemy dodawać inne zdarzenia może dojść do niepotrzebnego bałaganu w kodzie.  A przecież mamy jeszcze onBluronFocus, onChange itd. Jak zatem zrobić by wszyscy byli zadowoleni? Już śpieszę pokazać:

<a href="podstrona.html" class="odnosnik">kliknij mnie!</a>

Pewnie wielu z was zapyta „Dobra, a gdzie kod?”. Właśnie cała sztuczka polega na tym by rozdzielić kod HTML od JavaScript i wpakować ten drugi do sekcji head. Samo zdarzenie zaś podepniemy na podstawie dodanej klasy odnosnik.

Poniższy kod należy wstawić do sekcji head. Działa on bardzo prosto. Najpierw wszystkie istniejące na stronie odnośniki zapisujemy w tablicy elementya a potem w pętli sprawdzamy w każdym czy ma klasę odnosnik. Jeśli tak to podpinamy pod zdarzenie onClick funkcję  jakas_funkcja pamiętając o pominięciu nawiasów po nazwie a także o umieszczeniu return false; na końcu naszej funkcji.

var elementya = document.getElementsByTagName('a');
for(i=0; i < elementya.length; i++) {
     if (elementya[i].className=='odnosnik') elementya[i].onclick = jakas_funkcja;
 }

Zamiast pisać osobną funkcję możemy także stworzyć tzw. funkcję anonimową którą umieszcza się od razu w powyższym kodzie:

var elementya = document.getElementsByTagName('a');
for(i=0; i < elementya.length; i++) {
if (elementya[i].className=='odnosnik') elementya[i].onclick = function() { alert(';P'); return: false; };
}

Dodaliśmy zaledwie trzy linijki kodu a mamy pewność, że wszystko będzie działało tak jak trzeba na każdej przeglądarce. W razie nie działania JavaScriptu nic także nie będzie przeszkadzać by adres spod linku normalnie się wyświetlił. Taki coś jest potrzebne przy na przykład tworzeniu Ajaxowych komentarzy. Fajnie jak się dodają bez odświeżania strony ale skrypt musi także obowiązkowo działać gdy użytkownik będzie miał zablokowane wykonywanie skryptów w przeglądarce.

A bez href?

Jeśli nasz skrypt nie wymaga href w trybie bez JS to możemy np. upodobnić do odnośników element span:

<script>
    var elementy = document.getElementsByTagName('span');
    for(i=0; i < elementy.length; i++) {
    if (elementya[i].className=='klikacz') elementy[i].onclick = function() { alert(';P'); return: false; };
}
</srcipt>
<style>
   .klikacz{
        cursor: pointer;
   }
</style>
<span class="klikacz">Do złudzenia jak link</span>

W powyższym kodzie zmieniliśmy poszukiwane elementy na span a także za pomocą odpowiedniej klasy spowodowaliśmy, że najeżdzając na niego myszką kursor zamieni się na łapkę, tak jakby był to prawdziwy link.

10 odpowiedzi do tego artykułu

  1. Może pierw się kolega nauczy JS a później będzie pisał inne herezje na stronie? Tak się nie tworzy zdarzeń w JS. Zachęcam do przeczytania: http://www.quirksmode.org/js/events_advanced.html

    • Elektryk

      W JavaScript to jest fajne, że można wiele rzeczy osiągnąć różnymi drogami. Nie ma aż tak tak dużego znaczenia którą metodę użyjemy jeśli obie są bardzo podobne. Twój sposób jest bardziej tworzony od podstaw i jest dobry, mój pozwala na szybkie dodawanie zdarzeń dla wszystkich elementów z tą samą klasą, jak w jQ. Wyniki działań obu kodów są jednak identycznie.

  2. Elektryk, nie dobijaj mnie, jak chcesz mi powiedzieć że lepiej jest prze-iterować wszystkie elementy w DOM o tagu „a” lub „span” i przypisać im akcje click to proszę Cie pomyśl o wydajności takiego skryptu.

    • Elektryk

      No tak, wtedy lepiej użyć Twojej metody. Ale co jeśli chcemy dodać to zdarzenie większej ilości elementom i nie wiemy ile ich będzie na stronie? Twój sposób jest dobry gdy chcemy dodać zdarzenie konkretnym elementom, które znamy i wiemy ile ich jest, moja zaś jest w sam raz dla dołączanych bibliotek gdzie użytkownik tylko wpisuje klasę a skrypt sam wyszukuje wszystkie elementy za niego i nie trzeba pisać kolejnych linijek dla każdego np obrazka.

      • zegarek84

        Ale co jeśli chcemy dodać to zdarzenie większej ilości elementom i nie wiemy ile ich będzie na stronie? Twój sposób jest dobry gdy chcemy dodać zdarzenie konkretnym elementom, które znamy i wiemy ile ich jest, moja zaś jest w sam raz dla dołączanych bibliotek gdzie użytkownik tylko wpisuje klasę a skrypt sam wyszukuje wszystkie elementy za niego i nie trzeba pisać kolejnych linijek dla każdego np obrazka.

        od tego w jQuery jest metoda .live które działa w ten sposób, że da document jest podpięte jedno zdarzenie i analizowany jest target z propagacji zdarzenia w górę ;]
        poczytać o zasadzie działania możesz np. tutaj:
        http://www.quirksmode.org/js/events_order.html
        oczywiście nie w każdej przeglądarce jest .target ale jQuery to normuje w bardzo prosty sposób
        luknij jeszcze na temat na forum.php.pl
        [jquery] Dynamiczne dzieci
        gdzie w czystym js podpiąłem tylko jedno zdarzenie na nie istniejące jeszcze elementy w drzewie DOM (a w zasadzie nie na nie choć je „nasłuchiwałem”) – z jQuery skorzystałem tam tylko dla unormowanego obiektu event…

        • Elektryk

          Ale to nie jest tutorial w którym używany jest jQuery. Tam to by nie było żadnego problem bo wystarczy dać $(‘.klasa’).click();

          • zegarek84

            pisałem trochę o innej rzeczy – weź sobie wyobraź jakieś narzędzie i w tym narzędziu np. masz 1000 możliwych elementów do obsłużenia – i na każdy zamierzasz dać nasłuch z osobna?? nawet korzystając z jQuery i pisząc w stylu $(‘.klasa’).click(function(){}); podepniesz pod 1000 elementów nasłuch ale dla każdego z osobna niestety…

            mi bardziej chodziło o czysty JavaScript i technikę przypominającą .live z jQuery – jednak live podpina zdarzenie na cały dokument i gdzie byś nie kliknął to zdarzenie będzie analizowane nawet jeśli ustalisz context…

            jest co prawda metoda w jQuery dostępna od wersji 1.4.2 i nazywa się .delegate

            opisana metoda (nasłuch na jednym obiekcie drzewa DOM) jest optymalniejsza niż nasłuch na tysiącach elementów drzewa DOM – choć ta metoda jest głównie stosowana przez większość by obsłużyć elementy istniejące w strukturze później…

            i oczywiście w czystym js zamiast jQuery albo prosto dopisujesz zdarzenie .onclick = function(){…} albo jeśli masz kilka zdarzeń na document lub body przez .addEventListener a w IE .attachEvent i odpowiednio do tego przykładu co masz na forum w normalnych przeglądarkach kliknięty element masz pod e.target a w IE pod event.srcElement i przez propagację w górę można sprawdzić rodziców czy czasami nie mają jakichś atrybutów by ich obsłużyć lub sprawdzać bezpośrednio kliknięte dziecko…

          • Elektryk

            Czyli po prostu proponujesz metodą aby podpiąć jeden nasłucha dla wielu elementów. Musze przyznać, że wcześniej o tym nie słyszałem. Na pewno przyjrzę się temu i może napiszę o tym poradnik. Bo możliwość podpinania zdarzeń pod elementy które dopiero powstaną brzmi super.

          • zegarek84

            tak – dokładnie to miałem na myśli – sposób jak to „byle jak” zrobić w czystym js jest we wspomnianym temacie na forum.php.pl gdzie się wypowiadałem – jQuery tam tylko posłużyło jako szybszy przykład by mieć pod obiektem event właściwość .target (gdzie w IE trzeba by się odwołać inaczej do event.srcElement)…

            na podobnej zasadzie działa w jQuery .live (ale podpina nasłuch aż na całym dokumencie ;/) i dostępny od roku .delegate (gdzie nasłuch na zdarzenie jest podpięty do ustalonego elementu drzewa)… z tym, że nie na tej samej a na podobnej gdyż przeszukując elementy w górę zdarzenia są one sprawdzane pod kontem dopasowania do selektorów… w podanych przykładach na forum ja zrobiłem proxy/przypisanie callback’a tylko na podstawie nazwy klasy…

  3. No to z tym to się zgodzę. W końcu coś mądrego ;]

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

*

Możesz użyć następujących tagów oraz atrybutów HTML-a: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Markup Controls
Emoticons Smile Grin Sad Surprised Shocked Confused Cool Mad Razz Neutral Wink Lol Red Face Cry Evil Twisted Roll Exclaim Question Idea Arrow Mr Green