Home > Javascript | Web Programlama > Javascript’de Event ve Etki Alanı(Scope)

Javascript’de Event ve Etki Alanı(Scope)

Posted on 11 Şubat 2007 | 7 Yorum

Eğer javascript’de kendi framework’ünüzü geliştiriyorsanız muhtemel karşılaşacağınız sorunlardan bir tanesi de cross browser -her browser’da çalışabilecek- bir event sistemidir. Çünkü gerek Mozilla’da ve gerekse Internet Explorer’da event fonksiyonları ve buna bağlı olarak gelişen sonuçları farklı farklıdır. Ben bunların hangisinin haklı veya başarılı olduğundan bahsetmeyeceğim.

Bu yazımızda kendi oluşturduğunuz bir html nesnesine nasıl eventlar tanımlayabiliyoruz ve cross browser olarak nasıl çalıştırabiliriz, onu görmeye çalışacağız. Ayrıca event listener’daki scope problemi içinde bazı çözümler getireceğiz.

Halen, geliştirmekte olduğum framework’de de bir çok event sorunu ile karşılaştım. En başta, browser’dan browser’a fonksiyonların farklı olması, bunları tek bir çatı altında toplama gereğini hissettirdi. Bu nedenle IE’de ve Mozilla’da çalışabilen tek bir komut yapmalıydım.

Å?imdi dilerseniz, IE ve Mozilladaki farklılıklara göz atalım. Aşağıda IE’de ve Mozilla’da bir nesneye nasıl event listener eklendiğini görmektesiniz.

var mybutton = document.getElementById("MyButton");
//Aşağıdaki satır IE için
mybutton.attachEvent('onclick', mybutton_onclick);
//Aşağıdaki satır ise Mozilla için
mybutton.addEventListener('click', mybutton_onclick, false);
function mybutton_onclick(e)
{
    alert ("e = " + e);
    alert ("'this', window objesi mi? = " + (this === window));
}
<input type=&quot;Button&quot; id=&quot;MyButton&quot; />

Bu haliyle iki browser’da da hata verecektir. IE ve Mozilla’da ayrı ayrı bu kodları denediğinizde, IE’de addEventListener ve Mozilla’da attachEvent metodlarının tanımlı olmadığını göreceksiniz.. Aynı şekilde, IE’de (Mozilla için olan satırı sildikten sonra…) bu kodları çalıştırdığınızda ve "MyButton" isimli button’a tıkladıktan sonra "e"’nin tanımlı olmadığını göreceksiniz. IE7′de ise tanımlı olduğunu göreceksiniz. Normalde Mozilla’da ve IE7′de "e" parametresi ile event’ın nesnesi gelecektir. Ve siz de bu nesnenin özelliklerini kullanarak event’a ait bilgileri alabileceksiniz. Mesela hangi noktalara tıklandığını öğrenebilmek için e.clientX ve e.clientY gibi özellikleri alabileceksiniz. Ama IE6 ve öncesinde bunun yerine window.event gibi bir nesneden bunu sağlayabiliyorsunuz.

Yine, mybutton_onclick fonksiyonunda this ifadesi IE’de window‘u gösterirken, Mozillada event’a sahip olan nesneyi, yani bu örnekte "mybutton" nesnesini gösterir. İnternet üzerinde araştırma yaptığınızda bununla ilgili bir çok fonksiyon görebileceksiniz. Ama benim gibi kendi görsel nesnelerinizi tasarlıyorsanız, bulacağınız bu fonksiyonlar pek de işe yaramayacaktır. Özellikle etki alanı(scope) noktasında sorunlar yaşayacaksınız.

Mesela bütün nesnelerinizi türettiğiniz bir fonksiyon olsun ve siz buna event ekleyen bir metod eklemek istiyorsunuz. Bu durumda, event listener (yukarıdaki örnekte mybutton_onclick) içinde this işaretçisinin daima sizin nesnenizi göstermesini istersiniz. Ama IE’de bu işaretçi window‘u gösterirken, Mozilla’da da html nesnesini gösteriyordu.

İşte yukarıda saydığımız gibi sorunları çözebilmek için aşağıdaki gibi iki metod geliştirdim. Nesnemizin ismini MyControl olarak kabul edelim. Ve bu MyControl içinde bir metod(getElement) gerçek html nesnesini versin.

/**
 * Event listener ekler.
 * Event tetiklendiğinde fonksiyona event'ın nesnesini parametre olarak yollar.
 * @param {String} type click, mouseover, keyup vs...
 * @param {Function} listener çalıştırılacak olan fonksiyon
 */
MyControl.prototype.addEventListener = function(type, listener)
{
    var element = this.getElement(); //nesnenizdeki gerçek html elamanını verir.
    var self = this;
    var scopeFunction = function(e){
        return listener.call(self, e);
    };
    this.Events[type + listener] = function(e){
        if (typeof(e) !== &quot;undefined&quot;)
            scopeFunction(e);
        else
            scopeFunction(window.event);
    };
    if (document.attachEvent) //IE5+
        element.attachEvent('on' + type, this.Events[type + listener]);
    else//Mozilla, Safari, vs..
        element.addEventListener(type, this.Events[type + listener], false);
};

/**
 * @param {String} type
 * @param {Function} listener
 */
MyControl.prototype.removeEventListener = function(type, listener)
{
    var element = this.getElement();
    if (document.detachEvent)
        element.detachEvent('on' + type, this.Events[type + listener]);
    else
        element.removeEventListener(type, this.Events[type + listener], false);
    this.Events[type + listener] = null;
};

Bu metodlar MyControl isimli bir nesneniz olduğu varsayımı ile yazılmıştır. Aynı şekilde getElement() metodu da div, p, table gibi gerçek html nesnelerini dönderiyor. Bu metodları kendinize göre değiştirebilirsiniz.

Eğer sadece istediğiniz bir etki alanında event ekleyen basit bir fonksiyon yapmak isteseydik, yani nesne, sınıf olayına girmek istemeseydik, yukarıdaki fonksiyonları şu şekilde değiştirmemiz gerekecekti:

function addEventListener (element, type, listener, scope)
{
    var scopeFunction = function(e){
        return listener.call(scope, e);
    };
    element[type + listener] = function(e){
        if (typeof(e) !== &quot;undefined&quot;)
            scopeFunction(e);
        else
            scopeFunction(window.event);
    };
    if (document.attachEvent) //IE5+
        element.attachEvent('on' + type, element[type + listener]);
    else//Mozilla, Safari, vs..
        element.addEventListener(type, element[type + listener], false);
};

function removeEventListener (element, type, listener)
{
    if (document.detachEvent)
        element.detachEvent('on' + type, element[type + listener]);
    else
        element.removeEventListener(type, element[type + listener], false);
    element[type + listener] = null;
};

Ekstradan element ve scope diye iki parametre daha ekledik. "element" parametresi, div, p, button gibi html elementleri. Scope ise listener’ın çalıştırılacağı kapsama alanı. Peki bunu nasıl kullanacağız? Cevabı aşağıdaki küçük örnekte:

var mybutton = document.getElementById(&quot;MyButton&quot;);
addEventListener(mybutton, &quot;click&quot;, mybutton_onlick, mybutton_onlick);
function mybutton_onlick(e)
{
    alert(this);
}

Scope parametresine istediğiniz nesneyi ve fonskiyonu girebilirsiniz. Bu durumda button’a tıklandığında this işaretçisi belirtmiş olduğunuz nesne ya da fonksiyon olacaktır. Bu örneğimizde scope olarak mybutton_onclick fonksiyonunu seçtik. İsterseniz buraya, mybutton, window, document gibi nesneleri de girebilirsiniz. Burası size kalmış.

Hataları bildirirseniz sevinirim. Yorumlarınızı bekliyorum.

» Tags: , , , , , , , ,

7 Yorum

  • At 2007.02.11 20:57, Mustafa KUTLU said:

    Gerçekten çok güzel bir konuya temas etmişsin. Ben bu konulara uzak olsamda bu problem hepimizin karşılaşmış olduğu ve mutlaka çözüme ulaştırılması gereken bir konu. Neden IE desteklerken Mozilla desteklemiyor yada tam tersi. Bir bankanın sitesine IE ile girebiliyorken Firefox ile giremiyorum. Bu bankanın teknik destek kısmına gerek telefonla gerek birebir müracaat ile şikayette bulunsamda herhangi bir gelişme olmadı. Yani kocaaaamaannn banka siteleri bile buna dikkat etmiyor. Aslında dikkat edilmesi gereken çok önemli bir nokta. Fatih bu konuda ellerine sağlık demek az kalır. Ama ne yapalım yanında da olamadığım için yemek ısmarlıyamıyorum. Å?imdilik bununla idare et. :) vesselam.

    • At 2007.02.12 01:12, Fatih Tolga Ata said:

      Sen merak etme, o yemeği yemesini biz biliriz. :P

      • At 2007.02.12 09:30, Mustafa KUTLU said:

        Doğanbir diye birisi varmış, tanıyormusun? Yemek ısmarlama konusunda üzerine yokmuş diyorlar. Yani sanal alemin en bonkör deliganlısıymış dedüklerine göre ?

        • At 2007.11.16 16:33, özkan danacı said:

          öncelikle herkese kolay gelsin ;

          ben bu siteye yazmak istiyorum. Bunun için ne yapmam lazım acaba. İlgilenirseniz sevinirim. Güzel şeyler yazacağıma inanıyorum.

          • At 2007.11.17 04:47, Fatih Tolga Ata said:

            Bunu diyezondaki diğer arkadaşlarla görüşmemiz gerekiyor. Eğer böyle bir karar alınırsa sitenin ana sayfasından makale yazmak isteyenler için bir duyuru yapılacaktır.

            • At 2007.11.23 13:01, özkan danacı said:

              herkese kolay gelsin. uzman arkadaşlara bi sorum var. bir div elemanım var içine bir div create ediyorum (appendChild) sonra onu siliyorum sonra tekrar aynı isimde create ediyorum sonra tekrar silmeye çalışıyorum firefox hata veriyor “ben id sini verdiğin elemanın anasını tanımıyorum diyor.” ama yine aynı div elemanının içine create ediyorum, farklı tarafa değil. 2.create edildikten sonra sıra mı değişiyor, ne oluyor anlayamıyorum. bilgisi olan bi arkadaş varmı bu konuda acaba.

              • At 2010.02.03 14:21, Bülent Artüz said:

                Merhaba,
                Ben bugüne kadar sadece IE için program yazıyordum. Programlarımı bitirdim ve cross-browser olayına bi giriim dedim. O firefox, o opera, o safari, o chrome ne kadar aptalmış. Bi de millet onları savunuyor.

                Ben programlarımda değişiklik yapmayı hiç düşünmedim. Yani o browser için böyle bu browser için böyle olmasını istemiyorum. Ben bildiğim komutlarda eventlerde yazayım ama bütün browserlarda çalışsın istedim.

                Bunun için araştırma yoğunluğumu daha çok diğer browserlarda IE gibi davrandıracak inculude lara yönelttim.

                Belki sizinde sorununuzu çözecek bir sonuca ulaştım.
                ie_methods.js diye bir include js buldum:

                http://www.mts.net/~tfriesen/dhtml/ie_methods.html

                özellikle insertAdjacentHTML() kullanıyordum ve FireFoxda çalışmıyordu. Şimdi artık çalışıyor.

                Sizde yukardaki linkden indirip kullanabilirsiniz.

              (Required)
              (Required, will not be published)

              Switch to our mobile site