molily: Linklisten mit Tooltips

Beitrag lesen

Hallo,

document.onmousemove = updateWMTT;

Du überwachst damit dokumentweit andauernd das Mousemove-Ereignis und bei jeder Mausbewegung wird die Position berechnet. Das ist im Grunde unnötig. Du könntest die Überwachung dann starten und stoppen, wenn sie benötigt wird, nämlich bei einem Mouseover bzw. Mouseout bei den fraglichen Elementen. Du könntest die Überwachung zudem auf diese Elemente eingrenzen.

function updateWMTT(e) {
x = (document.all) ? window.event.x + document.body.scrollLeft : e.pageX;
y = (document.all) ? window.event.y + document.body.scrollTop  : e.pageY;

Diese Objektabfrage ist wenig sinnig. Grundregel: Prüfe die Existenz derjenigen Objekte, die du auch zu nutzen gedenkst. »Browsererkennungen« über document.all sind unpassend. Du kannst hier sowieso einfach http://de.selfhtml.org/javascript/objekte/event.htm#client_x_y@ŧitle=clientX/Y verwenden, wenn mich nichts täuscht.

function showWMTT(id) {
wmtt = document.getElementById(id);
wmtt.style.display = "block"
}

function hideWMTT() {
wmtt.style.display = "none";
}

<a href="..." onmouseover="showWMTT('1')" onmouseout="hideWMTT()">...</a>

Auf diese Weise hast du ewig viel JavaScript-Code in deinem Dokument stehen. Zeitgemäßes JavaScript schreiben bedeutet, Inhalt, Präsentation und JavaScript-Interaktivität voneinander zu trennen (siehe Schichtenmodell und Verhaltensschicht). Dein jetziger Code ist überladen und umständlich zu ändern.

Deshalb verzichtet man mittlerweile zunehmend auf Inline-Event-Attribute und registriert alle Handler automatisch per JavaScript (das nennt sich dann unobtrusive JavaScript oder DOM Scripting). Im HTML notiert man eine einfache Liste, die beim Laden des Dokuments durchlaufen wird. Dabei werden die Mouseover- und Mouseout-Handler registriert.

Genauer gesagt muss man gar nicht bei jedem Element einzeln Event-Handler registrieren. Mouseover-, Mouseout- und Mousemove-Ereignisse steigen auf (Bubbling). Man braucht also einfach ein Container-Element, bei dem alle Ereignisse vorbeilaufen, dort greift man sie ab und verarbeitet sie.

Das HTML kann entsprechend vereinfacht werden, es wird kein JavaScript-Code darin mehr untergebracht. Ich habe mal als Beispiel eine Definitionsliste gewählt:

<dl class="linkliste">  
<dt><a href="http://www.example.org/">aaaaaa</a></dt>  
<dd>aaaaaa</dd>  
<dt><a href="http://www.example.org/">bbbbbb</a></dt>  
<dd>bbbbbb</dd>  
<dt><a href="http://www.example.org/">cccccc</a></dt>  
<dd>cccccc</dd>  
<dt><a href="http://www.example.org/">dddddd</a></dt>  
<dd>dddddd</dd>  
<dt><a href="http://www.example.org/">eeeeee</a></dt>  
<dd>eeeeee</dd>  
</dl>  

Das Script im Dokumentkopf könnte zeitgemäß etwa so aussehen:

<style type="text/css">  
[code lang=css].linkliste dd.hidden { position:absolute; left: -9000px; top:0; width: 0; overflow: hidden; }  
.linkliste dd.visible { padding:0.5em; width: 15em; overflow: auto; border:1px solid black; background-color:#eee; }

</style>
<script type="text/javascript">

  
/* Wenn JavaScript aktiviert ist, verstecke alle dd-Elemente standardmäßig mit der [link:http://www.access-matters.com/testcases/tc5-2-9.html@title=Off-Left-Methode]. Die ist besser als ein einfaches display:none, weil Screenreader-Benutzer den versteckten Text dann trotzdem lesen können. */  
document.write("<style type='text/css'>" +  
".linkliste dd { margin:0; padding:0; position:absolute; left: -9000px; top:0; width: 0; overflow: hidden; }" +  
"</style>");  
  
/* Führe beim Laden der Seite die Methode tooltip.init() aus. */  
window.onload = function () {  
 tooltip.init();  
};  
  
/* Erzeuge ein allgemeines Objekt, das lediglich als Container-Objekt für ein paar Variablen und Funktionen dient. So kann man zusammenhängenden JavaScript-Code übersichtlicher strukturieren, denn alle Tooltip-bezogenen Funktionen sind Methoden des Objektes tooltip. */  
var tooltip = new Object();  
tooltip.current_dt = null;  
tooltip.current_dd = null;  
  
/* Initialisierungsmethode */  
tooltip.init = function () {  
 /* Suche alle dl-Elemente im Dokumente */  
 var dl_elements = document.getElementsByTagName("dl");  
 /* Durchlaufe die gefundene Elementliste */  
 for (var i = 0, dl_element, j = 0, dt_element; i < dl_elements.length; i++) {  
  dl_element = dl_elements[i];  
  /* Hat das dl-Element die Klasse linkliste? Wenn nicht, dann fahre mit dem nächsten Schleifendurchlauf fort. */  
  if (dl_element.className != "linkliste") {  
   continue;  
  }  
  /* Registriere alle Event-Handler zentral beim dl-Element. Bei jeglichen ...-Ereignissen, die bei dl-Element passieren oder vorbeikommen (beim Aufsteigen/Bubbling), führe ... aus */  
  dl_element.onmousemove = tooltip.update;  
  dl_element.onmouseover = tooltip.show;  
  dl_element.onmouseout = tooltip.hide;  
 }  
};  
  
/* Beim Mouseover über irgendein Element innerhalb des dl-Elements wird diese Methode aufgerufen. */  
tooltip.show = function (e) {  
 /* Blende die letzte Linkbeschreibung aus, sofern bereits eine angezeigt wurde. */  
 if (tooltip.current_dd) {  
  tooltip.hide();  
 }  
 /* Zugriff auf das Event-Objekt, siehe [link:http://de.selfhtml.org/javascript/objekte/event.htm#allgemeines@title=SELFHTML] */  
 e = e || window.event;  
 /* Zugriff auf das Zielelement des Ereignisses (entweder das dl-Element selbst oder eines der dt-Elemente oder eines der Elemente darin, z.B. a) */  
 var target = e.target || e.srcElement;  
 /* Wir möchten vom Zielelement zum dt-Element, also steigen wir im DOM-Knotenbaum auf, bis wir dieses finden. */  
 var node = target;  
 while (node.nodeName != "DT" && node != null) {  
  node = node.parentNode;  
 }  
 /* Lege eine Referenz auf den gefundenen dt-Elementknoten an */  
 tooltip.current_dt = node;  
 /* Eigentlich wollen wir zum dd-Element, also müssen wir ausgehend vom dt-Element das zugehörige dd-Element finden. Es muss aber pro dt-Element nur einmal gesucht werden, auch wenn es mehrmals mit der Maus überfahren wird. Also wird eine Referenz auf den Knoten als Eigenschaft corresponding_dd an den dt-Elementknoten gehängt, die später dann direkt genutzt wird. */  
 if (tooltip.current_dt.corresponding_dd) {  
  /* Falls eine solche Referenz bereits angelegt wurde, dann benutze diesen dd-Elementknoten. */  
  tooltip.current_dd = tooltip.current_dt.corresponding_dd;  
 } else {  
  /* Das zugehörige dd-Element muss erst gesucht werden. Durchlaufe alle dem dt-Element nachfolgenden Knoten, bis ein dd-Elementknoten gefunden wird. */  
  while (node.nodeName != "DD" && node != null) {  
   node = node.nextSibling;  
  }  
  /* Lege Referenzen auf den den gefundenen Elementknoten an */  
  tooltip.current_dd = tooltip.current_dt.corresponding_dd = node;  
 }  
 /* Zeige das dd-Element mit der Beschreibung */  
 tooltip.current_dd.className = "visible";  
 //tooltip.update(e);  
};  
  
/* Positioniere das gegenwärtige dd-Element (bei dem das letzte Mouseover-Ereignis passierte) entsprechend der Mausposition */  
tooltip.update = function (e) {  
 e = e || window.event;  
 tooltip.x = e.clientX;  
 tooltip.y = e.clientY;  
 /* Über tooltip.current_dd kann hier einfach auf den dd-Elementknoten zugegriffen werden. */  
 tooltip.current_dd.style.left = (tooltip.x + 20) + "px";  
 tooltip.current_dd.style.top = (tooltip.y + 20) + "px";  
};  
  
/* Verstecke das letzte gezeigte dd-Element */  
tooltip.hide = function () {  
 tooltip.current_dd.className = "hidden";  
 tooltip.current_dd.style.left = "-9000px";  
};

</script>
[/code]

Der JavaScript-Code ist vergleichsweise komplizierter, diese Art des Event-Handlings und dieser Programmierstil macht es einem aber auf lange Sicht viel einfacher. Vor allem sind die Inhalte auch ohne JavaScript zugänglich und der HTML-Code hat eine ordentliche Struktur.

(Tastatur-Zugänglichkeit ist noch nicht gegeben, sprich, die Beschreibungen werden nicht eingeblendet, wenn ein Link mit der Tastatur angesprungen wird. Da schlägt die Nutzung des Bubblings fehl, weil Focus-Ereignisse nicht aufsteigen.)

Mathias