Berker Peksağ.

15 Nisan 2008, Salı;

DOM (Document Object Model/Belge Nesne Modeli)

Saat: 13:12:45, Programlama

Başlarken

DOM(Document Object Model/Belge Nesne Modeli) konusuna girmeden önce yazı boyunca sıkça kullanacağımız kelimeler hakkında birkaç tanım yapıp, İngilizce karşılıklarını da vermekte fayda görüyorum.

Düğüm(Node): Geçerli her HTML ve XML belgesindeki element, nitelik, metin düğümü(text node) hatta boşluk ve sekme karakterleri(whitespace) bile W3C DOM tarafından düğüm olarak kabul edilir.

Düğüm ağacı(Node tree): Belgedeki düğümlerin kullanım hiyerarşisine göre sıralanmasına denir.

Örnek 1: Basit bir düğüm ağacı

<html>
    <head>
        <title>Sayfa başlığımız</title>
    </head>
    <body>
        <p class="selam">
            Deneme <strong>mesajımız.</strong>
        </p>
    </body>
</html>

Yukarıdaki örneğin düğüm hiyerarşisiyse aşağıdaki gibidir:

document
- <html>
- - (whitespace)
- - <head>
- - (whitespace)
- - <title>
- - - Sayfa başlığımız
- - - (whitespace)
- - <body>
- - (whitespace)
- - - <p class="selam">
- - - (whitespace)
- - - - Deneme
- - - - - <strong>
- - - - - - mesajımız.
- - - - -
(whitespace)

Burada unutulmaması gereken ana nokta, Inrernet Explorer’ın boşluk ve sekme karakterlerini yok saymasıdır ki bu da JavaScript ile düğümlere erişirken tarayıcılar arasında yaşanan problemlerin en önemli sebeplerinden birini oluşturur.

İsterseniz, düğüm özellikleri(node properties) ve JavaScript ile işlem yapmaya geçmeden önce, DOM tarihçesine göz atalım.

Nasıl doğdu?

DOM 0

Nesne Modeli kavramının ilk versiyonudur. Başlarda sadece Netscape Navigator tarafından tam olarak destekleniyordu. En büyük yeniliği, JavaScript ile sayfadaki HTML elementlerine erişmeye izin vermesiydi. Daha sonra Microsoft, Internet Explorer 3’te DOM 0’ı aynen destekledi. Tabii daha sonraları bu barış havasından pek eser kalmadı :)

DOM 0+Images

En önemli değişikliği, Netscape Navigator 3.0 ile birlikte sunulan Image nesnesiydi. Başlangıçta sadece src niteliği kullanılabilir olsa da o yıllarda geliştiriciler için yeterli olsa gerek :) Ama Microsoft, Image nesnesini desteklemeyerek bugün “Tarayıcı Savaşları”* adını verdiğimiz, tarayıcılar arasındaki uyumsuzlukların temelini attı.

Tarayıcı savaşları başlıyor!

Netscape Cephesi

Netscape Navigator 4.0 sürümüyle birlikte, olay yönetimi tamamen geliştiricinin kontrolü altına girdi. Olay yönetiminin temel çalışma prensibi; olayın tetiklendiği en üst noktadan başlayarak, gerçek nedeniyle doğru yayılması şeklinde açıklanabilir(bkz. Örnek 1).

Netscape Navigator 4.0’ın bir diğer yeniliği de katman mimarisi ve <layer> HTML elementiydi. Bu yeni element, sayfayı farklı katmanlara ayırmaya ve gerektiğinde nesneleri farklı katmanlar arasına taşımayı sağlıyordu.

Microsoft Cephesi

Microsoft, Internet Explorer sürümüyle birlikte tüm HTML elementlerine erişim imkanı sağladı. Ayrıca, bana göre yeni sürümdeki en büyük yenilik CSS için eklenen style özelliğidir. Bugün gelinen noktada, en çok kullanılan özelliklerden biri olduğunu söylemek yanlış olmaz.

Tüm bu yeniliklerin yanında, Microsoft’un Netscape’in olay yönetimine getirdiği farklı bakış açısı, tarayıcılar arası uyum sorunlarını farklı noktaya taşıdı. Internet Explorer 4, olay kabarcıkları(event bubbling) denilen, gerçek olay nedeninden başlayarak window nesnesine ulaşan bir işleyişe sahipti.

Bu farklılığın ortaya çıkardığı en büyük problem, olay yakalamada yaşanan farklılıklardı. Ancak günümüzde, modern tarayıcılarda kendi nesne modellerine ek olarak, W3C DOM level 2’nin de desteklenmesiyle büyük oranda çözülmüştür.

Son yenilik ise, halen diğer modern tarayıcılar ve W3C DOM tarafından desteklenmeyen filtrelerdir. Bu filtreler, başta saydamlık olmak üzere pek çok görsel değişikliğe olanak sağlamaktaydı.

Modern tarayıcılardaki son durum

Tarayıcılar arasında halen devam eden karışıklıklara rağmen, modern tarayıcılar kendi nesne modelleri yanı sıra, W3C DOM'u da destekleyerek geliştiricilerin işini bir nebze de olsa kolaylaştırmaya başladı. Buna rağmen örneğin, Microsoft Internet Explorer ve Mozilla Firefox'ta JavaScript ile herhangi bir yazıyı kopyalamak için iki farklı kod yazmak zorunda kalıyoruz.

W3C DOM

W3C DOM, yukarıdaki paragraflarda da anlattığımız tarayıcılar arası farklılıkları ortadan kaldırmak amacıyla, önde gelen tarayıcı üreticilerinin de desteğiyle geliştirilmeye başlanmıştır. W3C DOM Level 2, tüm tarayıcılar tarafından desteklenen en güncel sürümdür. W3C DOM Level 3, halen geliştirilme aşamasındadır. Başta olay yönetimi olmak üzere birçok konuda büyük değişikler yaşanacaktır. HTML 5'in tamamlanmasıyla ortaya çıkışının fazla zaman almayacağını umuyorum :)

Düğümlere erişmek

Düğümlere erişmek ve yönetmek için kullanacağımız üç ana JavaScript metodu vardır:

  1. getElementById()
  2. getElementsByTagName()
  3. getElementsByName()

getElementById()

Sözdizimi:
document.getElementById("herhangiBirID");

getElementById() metodu, belirtilen ID'nin kapsadığı elementleri döndürür. Ancak bu metod XML'de çalışmaz. XML DOM konusuna daha sonra –umarım 2008 içinde!- ayrı bir makalede değinmeyi düşünüyorum.

Örnek 2:

<div id="paragraf"><p>Bu paragraf çok şey anlatıyor.</p></div>


<script type="text/javascript">
    var oDiv = document.getElementById("paragraf");
    document.write(oDiv.firstChild.innerHTML);

</script>

getElementsByTagName()

Sözdizimi:
document.getElementsByTagName("herhangiBirHTMLElementi");

Örnek 3:

document.getElementsByTagName("a");

Belge içerisindeki tüm <a> elementlerini verir.

document.getElementById("herhangiBirID").document.getElementsByTagName("img");

id niteliğinin değeri "herhangiBirID" olan elementin düğümleri içindeki tüm <img> elementlerini verir.

getElementsByName()

Sözdizimi:
document.getElementsByName("herhangiBirIsim");

Örnek 4:

document.getElementsByName("baslik");

name niteliğinin değeri "baslik" olan elementleri verir.

Düğümler arasında dolaşmak: firstChild, lastChild, parentNode

firstChild

Düğümün ilk çocuk düğümüne erişir.

Sözdizimi:
document.getElementById("herhangiBirID").firstChild;

Örnek 5:

<a href="#" id="deneme">Link 1</a>

<script type="text/javascript">
    var oDiv = document.getElementById("deneme");
    document.write(oDiv.firstChild.nodeValue);

</script>

lastChild

Sözdizimi:
document.getElemementById(“herhangiBirID”).lastChild;

Örnek 3:

<p id="paragraf"><a href="#">Link 1</a><a href="#">Link 2</a></p>

<script type="text/javascript">
    var oDiv = document.getElementById("paragraf");
    document.write(oDiv.lastChild.firstChild.nodeValue);

</script>

parentNode

Son örnekten yola çıkarak açıklamaya çalışırsam, <p> elementi tüm çocuk(child) elementların ana(parent) düğümüdür.

Düğümlerin değerlerini almak: nodeValue

Sözdizimi:
document.getElemementById(“herhangiBirID”).lastChild.nodeValue;

Örnek 4:

<script type="text/javascript">
    var deger = document.getElementById(“nav”).firstChild.nodeValue;
    document.write(deger);

</script>

Herhangi bir elementin ilk düğümünü silmek: removeChild

Sözdizimi:
var o = document.getElementById(“nav”);
o.parentNode.removeChild(o);

Örnek 5:

<p id="paragraf2"><a href="#">Link 1</a><a href="#">Link 2</a></p>

<script type="text/javascript">
    var oDiv = document.getElementById("paragraf2");
    document.write(oDiv.parentNode.removeChild(oDiv));

</script>

Bir çocuk düğümü başka bir çocuk düğümle değiştirmek: replaceChild

Örnek 6:

<p>
    "That is not dead<br />
    Which can eternal lie<br />
    Yet with strange aeons<br />
    Even death may die"
<br /><br />
    <strong id="yazar">H. P. Lovecraft</strong>
</p>

<button type="button" onclick="fnReplace()">Değiştir</button>

<script type="text/javascript">
    function fnReplace() {
        var o = document.createElement("strong");
        var oIcerik = document.createTextNode("Steve Harris");
        o.appendChild(oIcerik);

        var o2 = document.getElementById("yazar");
        var anneElement = o2.parentNode;
        anneElement.replaceChild(o, o2);
    }

</script>

Düğüm bilgilerini almak: nodeName, nodeType

nodeName

Geçerli düğümün adını döndürür. Geçerli  düğüm element ise, elementin tipini döndürür. Nitelik ise, nitelik adını döndürür.

nodeType

Geçerli düğümün türünü sayısal olarak döndürür.

1 – Element
2 – Attribute
3 – Text
4 – Comment
5 – Document

Çocuk düğümleri(child nodes) almak: childNodes

İşaret edilen düğümün eğer varsa, çocuk düğümlerini bir dizide depolar.

Düğümler arası gezinti: nextSibling, previousSibling

nextSibling

Geçerli düğümden bir sonrakine referans verir.

previousSibling

Geçerli düğümün bir öncekine referans verir.

Yeni bir çocuk düğüm eklemek: appendChild

Söz dizimi:
document.getElementById(“birID”).appendChild(oDugum);

Örnek 7:

<input type="text" name="frmAlbum" id="idAlbum" value="" />

<button type="button" onclick="fnAlbumEkle()">Ekle</button>

<ul id="liste">
    <li>Iron Maiden</li>
    <li>Killers</li>
</ul>

<script type="text/javascript">
     function fnAlbumEkle() {
          var strAlbum = document.getElementById("idAlbum").value;
          var o = document.createElement("LI");
          o.innerHTML = strAlbum;
          document.getElementById("liste").appendChild(o);
     }

</script>

Bir düğümün niteliklerine erişmek: getAttributeNode

Sözdizimi:
element.getAttributeNode(nitelik);

Örnek 8:

<p id="nitelikAdimiz" class="uyari">
    Metallica 3. kez Türkiye'de konser verecek!
</p>

<script type="text/javascript">
    var o = document.getElementById("nitelikAdimiz");
    var nitelik = o.getAttributeNode("class");
    document.write(nitelik.value);

</script>


Bir düğüme nitelik atamak: setAttributeNode

Sözdizimi:
element.setAttributeNode(nitelik);

Örnek 9:

<p id="nitelikAdimiz3" class="uyari">
    "That is not dead<br />
    Which can eternal lie<br />
    Yet with strange aeons<br />
    Even death may die"<br /><br />
    H. P. Lovecraft

</p>

<p id="nitelikAdimiz4">
    "That is not dead<br />
    Which can eternal lie<br />
    Yet with strange aeons<br />
    Even death may die"<br /><br />
    H. P. Lovecraft

</p>

<button type="button" onclick="fnEkle()">class="uyari" ekle</button>

<script type="text/javascript">
    function fnEkle() {
        var o1 = document.getElementById("nitelikAdimiz3");
        var o2 = document.getElementById("nitelikAdimiz4");
        var nitelikAta = o1.getAttributeNode("class");
        o1.removeAttributeNode(nitelikAta);
        o2.setAttributeNode(nitelikAta);
    }

</script>


Bir nitelik düğümünü silmek: removeAttributeNode

Örnek 10:

<p id="nitelikAdimiz2" class="uyari">
    "That is not dead<br />
    Which can eternal lie<br />
    Yet with strange aeons<br />
    Even death may die"<br /><br />
    H. P. Lovecraft

</p>

<button type="button" onclick="fnNodeKaldir()">class="uyari" kaldır</button>

<script type="text/javascript">
    function fnNodeKaldir() {
        var o = document.getElementById("nitelikAdimiz2");
        var nitelik = o.getAttributeNode("class");
        o.removeAttributeNode(nitelik);
    }

</script>

Araçlar

DOM Inspector(DOMi)

Mozilla Firefox ile birlikte gelen DOM Inspector aracı başlangıç için oldukça işe yarar. Araçlar > DOM Inspector ya da CTRL + SHIFT + I kısayolunu kullanarak aracı başlatabilirsiniz. Arayüzü Firefox’a benzer olduğu için neyin ne olduğundan bahsetmiyorum.

Yazımız içerisinde Internet Explorer’ın boşluk ve sekme karakterlerini düğüm olarak yorumlamadığını söylemiştik. Arzu ederseniz View > Show Whitespace Nodes tikini kaldırarak, DOMi’ın aynı şekilde yorumlamasını sağlayabilirsiniz.

Firebug

Bir tarayıcı için yazılan eklentide bile kalitenin ne kadar yukarılara çekilebileceğinin kanıtıdır Joe Hewitt amca tarafından yazılan Firebug. Eklentiyi buradan kurabilir ve F12 tuşuyla aktive edebilirsiniz. Konsolu açtıktan sonra geriye kalan tek şey Inspect butonuna tıklamak.

Aardvark

Firebug gibi bir başka Firefox eklentisi daha. Firebug’a göre biraz daha kullanışlı olduğunu söyleyebilirim. Kurduktan sonra, kullanmak istediğiniz sayfada sağ tıklayıp Start Aardvark diyerek çalışmaya başlayabilirsiniz. Özellikle ana düğüm ve çocuk düğümlerle çalışırken işinizi epey kolaylaştırıyor.

Firebug Lite

Firebug’ın avantajlarından Internet Explorer, Opera ve Safari gibi popüler tarayıcılarda da yararlanmak için harika bir çözüm.

IE Developer Tools

Firefox’un DOM Inspector’ının Internep Explorer 8’deki karşılığı diyebiliriz kısaca. Henüz geliştirilme aşamasında olsa da benim kullandığım kısıtlı süre boyunca DOM Inspector’a göre daha kullanışlı olduğunu söyleyebilirim.

Son sözler

Her zamanki gibi işe koyulma tarihimle tamamlamam arasında epey süre geçti. Bu nedenle gözden kaçırdığım, yazım şeklinden kaynaklı düşük cümleler ve yanlış bilgiler olabilir. Eğer böyle bir sorunla karşılaşırsanız(ya da eklemek istedikleriniz varsa) lütfen bunu yazıya yorum yazarak ya da berker.peksag at gmail.com e-posta adresini kullanarak bildirmekten çekinmeyin.

Yararlanılan kaynaklar

  1. Inside JavaScript – Steven Holzner (New Riders Publishing, 2003)
  2. http://en.wikipedia.org/wiki/Document_Object_Model
  3. http://developer.mozilla.org/en/docs/Introduction_to_DOM_Inspector
  4. http://developer.mozilla.org/en/docs/DOM:element.setAttributeNode






Yorumlar



Yorumunuzu yazın

Kalın olarak belirtilen alanların doldurulması zorunludur. Yorumunuz sayfada yayımlanmadan önce onaylanacak ve e-posta adresiniz üçüncü kişilerle paylaşılmayacaktır.

 

Ne yapıyorum? (twitter)


Sık kullanılanlar


Projeler


Takip ettiklerim


En son dinlediklerim (last.fm)

(c) Berker PEKSAĞ. 2004-2007

Yayımlanan yazılar, kaynak gösterildiği müddetçe kullanılabilir.
Eklenen yorumların sorumluluğu yazarına aittir.