JavaScript funkce: addEvent, removeEvent

Existuje pár funkcí, které se objevují prakticky v každém jen trochu rozsáhlejším JavaScriptovém kódu. Přesto nejsou součástí jazyka jako takového a nebo jsou, ale v každém prohlížeči fungují trochu jinak. Rád bych tu zahájil seriál, kde několik těchto užitečných fragmentů shromáždím. Nejprve se podíváme na obsluhu událostí.

Upozornění: Hledáte-li pouze zdroják bez zbytečné teoretické omáčky, přeskočte na konec článku.

Pro obsluhu nějaké události můžeme použít několik přístupů. Nejjednodušší je takzvaný tradiční model:

element.onclick = naseObsluznaFunkce;

Výhodou je - na JavaScript - neobvykle dobrá podpora v prohlížečích, což je natolik silný argument, že tradiční model někteří stále považují za nejlepší způsob, jak obsloužit událost. Jste prakticky limitováni pouze typem událostí, které u konkrétního elementu daný prohlížeč podporuje.

Mimochodem, pokud umíte číst mezi řádky, brzy zjistíte, že např. onclick je také funkce. Čili lze bez problémů kdekoliv vyvolat obsluhu události click takto:

element.onclick();

Jak už to tak bývá, nic není stoprocentní, takže i tradiční model má své mouchy. Nelze příliš jednoduše navěsit více obslužných funkcí na jednu událost. Možnost tu je:

element.onclick = function() { obsluznaFunkce1(); obsluznaFunkce2(); };

Jenže takový způsob není příliš flexibilní. Musíte hned od začátku přesně vědět, které funkce na daný element chcete aplikovat. Dejme tomu, že provádíte kontrolu údajů ve formuláři pomocí JavaScriptu. Po nějakém čase se rozhodnete přidat do svého webu JavaScriptovou knihovnu, která po kliknutí na všechna tlačítka tato tlačítka obarví. Ouha! Pokud knihovna, která samozřejmě neví nic o vaší aplikaci, zaregistruje událost click tradičním způsobem, přepíše vaši obsluhu.

Řešení existuje aneb addEvent a removeEvent

Z tohoto důvodu přistoupili jak u W3C, tak u Microsoftu k vyvinutí pokročilého modelu registrace událostí. To je samozřejmě záslužné, pokud každá organizace nevyvine svůj vlastní model, který se od toho druhého diametrálně liší. Některé problémy byly natolik nepřekonatelné, že vedly k zavrhování pokročilého modelu.

Až jednou přišel jakýsi John Resig na svém blogu s konečným řešením:

/**
 *  Priradi urcite udalosti objektu zadanou obsluznou funkci. Rozhodne
 *  automaticky, zda pouzit attachEvent, nebo addEventListener. Resi problem
 *  s pouzitim this uvnitr obsluzne funkce.
 *  @param obj Objekt, u nehoz chceme udalost obsluhovat.
 *  @param event Udalost, jiz hodlame obslouzit - ve formatu click, load apod.
 *               (nikoliv onclick, onload).
 *  @param funct Nazev obsluzne funkce.
 */
function addEvent(obj, event, funct) {
  if (obj.attachEvent) { //IE
    obj['e' + event + funct] = funct;
    obj['x' + event + funct] = function() {
          obj['e' + event + funct](window.event);
        }
    obj.attachEvent('on' + event, obj['x' + event + funct]);
  } else // other browser
    obj.addEventListener(event, funct, false);
}

Protějšek pro odstranění události od určitého objektu následuje:

/**
 *  Odstrani zadanou obsluznou funkci registrovanou u objektu.
 *  @param obj Objekt, u nehoz chceme obsluznou funkci odstrani.
 *  @param event Udalost, jiz doposud funkce obsluhovala - ve formatu click,
 *               load apod. (nikoliv onclick, onload).
 *  @param funct Nazev obsluzne funkce, jiz planujeme odstranit.
 */
function removeEvent(obj, event, funct) {
  if (obj.detachEvent) { // IE
    obj.detachEvent('on' + event, obj[event + funct]);
    obj['x' + event + funct] = null;
  } else // other browser
    obj.removeEventListener(event, funct, false );
}

Děkujeme Johne!

Komentáře: 5 » přidat

  1. Richard Šerý

    Nevím jestli to tahle verze nedělá ale některé varianty téhle funkce způsobovaly memory leaky, tak pozor na to.

    Jinak viděl jsem knihovnu base2.DOM Deana Edwardse, která tohle řeší taky a to poměrně sympatickým způsobem - spraví totiž funkci addEventListener, takže není potřeba definovat žádné další funkce a v budoucnu, až vymřou archaické browsery, se prostě knihovna vyhodí a bude to fungovat i bez ní.

  2. admin

    Tahle verze by myslím memory leak způsobovat neměla, alespoň proto je v removeElement dle mého příslušná položka pole nullována: obj['x' + event + funct] = null;.

    Nápad s přepsáním addEventListener je každopádně zajímavá vychytávka. Ale obávám se, že Microsoft se svého modelu jen tak nevzdá, aby bylo možné knihovnu zahodit.

  3. Floroskop

    Hello!
    I think this try.

  4. Martin Zvarík

    Memleaky jsou problémem v IE 6 a řeší se to přes window.onunload = function(){ zruš všechny eventy }

    Event funkci v tomto článku nedoporučuji nikomu používat, a nedoporučuje to ani sám autor (byla to soutěž o nejkratší zápis) - alespoň tak jsem to četl na jeho webu.

  5. Aleš Zrak

    Pokud by se někdo dále zabýval touto problematikou, pak možná ocení následující odkaz na funkci, která vyšla jako vítězná z dané soutěže a ve které je opraveno právě těch pár drobností ohledně těch memleaků (aspoň to tam tak tvrdí ;) )

Přidat komentář

XHTML: Je možné používat tyto značky: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>