Orlok: stopPropagation nicht verstanden?

Beitrag lesen

problematische Seite

Hallo Linuchs

Ich habe noch nicht so ganz durchschaut was du hier zusammenbaust, aber so richtig gut schaut es nicht aus.

<img id="werbung" class="help" src="img/icon_info.png" alt="?" title="Info" />

Meinst du nicht, dass es einen aussagekräftigeren Alternativtext gibt als bloß ein Fragezeichen? Das wäre aus Benutzersicht wichtiger als ein title–Attribut, das die Mehrzahl der Benutzer vermutlich ohnehin nie zu Gesicht bekommen wird.

  var erster  = document.getElementsByTagName( "body" )[0].firstChild;

var erster? Für diese Wahl des Bezeichners gibt es wohl nicht die Goldmedaille. Mal angenommen, die Variable wäre nicht überflüssig, dann würde ich ihr einen Namen geben, unter dem man sich etwas vorstellen kann. – Vielleicht firstChild?

// Für ältere Browser über Elementausdrücke

var firstChild = document.body.firstChild;


// In modernen Browsern auch mittels Destrukturierung

const {firstChild} = document.body;

Du musst übrigens nicht mit getElementsByTagName eine HTMLCollection der body–Elemente erzeugen. Ich meine, ich will nicht hoffen, dass in deinem Dokument mehr als ein body–Element vorkommt. Das eine kannst du dann direkt über document.body referenzieren.

  document.body.insertBefore( newDiv, erster );

Na sowas, hier ist dir das mit document.body ja wieder eingefallen. 😉 Da du das erste Kindelement von body nur an dieser Stelle brauchst, hättest du es auch direkt in den Ausdruck einsetzen können. Wäre so vielleicht ein wenig besser lesbar.

// Fügt das div vor dem ersten Kindelement von body ein

document.body.prepend(helptext);

Wenn du Internet Explorer und andere antiquierte Browser nicht mehr unterstützen willst, könntest du statt insertBefore an dieser Stelle übrigens auch die Methode prepend verwenden, um den Hilfetext als erstes Kind des body–Elements hinzuzufügen. Eine Referenz auf den ersten Kindknoten ist bei Verwendung dieser Methode nicht nötig.

Ein Polyfill für ältere Browser ist übrigens schnell gebaut:

if (!Element.prototype.prepend) {

    Element.prototype.prepend = function prepend() {
        var fragment = document.createDocumentFragment();

        Array.prototype.forEach.call(arguments, function(value) {
            fragment.appendChild(
                value instanceof Node
                    ? value
                    : document.createTextNode(value)
            );
        });

        this.insertBefore(fragment, this.firstChild);
    };

}

Ist aber ungetestet.

  obj_help = document.getElementsByClassName( "help" );

Hier legst du eine globale Variable an. Sofern du nicht in der äußeren lexikalischen Umgebung deiner Funktion eine lokale Variable gleichen Namens deklariert hast, an die du zuweist. Globale Variablen möchtest du sicherlich vermeiden, also verwende wenn nötig var, oder besser gleich const. – Eine erneute Zuweisung wird hier offenbar nicht vorgenommen.

Buchstaben sind übrigens keine Mangelware. Du möchtest wohl wenigstens noch ein 'e', ein 'c' und ein 't' für den Bezeichner kaufen. Immerhin postest du den Code hier, möchtest also, dass auch andere ihn gut lesen können.

Es ist oft auch eine gute Idee, Namen von Variablen, die für Sammlungen – also eine Vielzahl von Objekten stehen, im Plural zu notieren. Zum Beispiel hättest du im vorliegenden Fall helpObjects oder helpers schreiben können.

In JavaScript ist es übrigens Konvention, bei Bezeichnern camelCase und nicht snake_case zu verwenden, so wie du es weiter oben auch getan hast. Unabhängig davon welche Variante du wählst, solltest du aber mindestens innerhalb eines Skripts bei dieser Variante bleiben. Beide Stile zu mischen fördert die Lesbarkeit nicht.

<img id="werbung" class="help" src="img/icon_info.png" alt="?" title="Info" />

Ich füge an dieser Stelle nochmal das Markup vom Anfang ein, für den Fall, dass irgendjemand die Zeile bereits vergessen hat.

  obj_help = document.getElementsByClassName( "help" );

Wir halten fest: Was in der Variable obj_help gespeichert wird, ist also eine HTMLCollection, die mindestens ein img–Element enthält. ✔️

  for ( i=0; i<obj_help.length; i++ ) {

Und wieder keine Variablendeklaration. Laufindizes als globale Variablen sind sehr nützlich wenn es darum geht, schwer auffindbare Programmfehler zu konstruieren.

for (let i = 0, length = helpers.length; i < length; i++) {

Wenn du für die Deklaration das Schlüsselwort let verwendest, dann ist der Index nur innerhalb des Anweisungsblocks der Schleife sichtbar. Wechselwirkungen mit gleichnamigen Variablen anderswo im Programm sind auf diese Weise ausgeschlossen. Verwendest du var, ist die Sichtbarkeit immerhin auf den lokalen Scope der Funktion begrenzt.

    if ( obj_help[i].id ) {

Du machst eine Entscheidung davon abhängig, ob irgendwelche Elemente eine id besitzen? Ganz allgemein und nicht etwa abhängig vom Wert des id–Attributs? Oder von anderen Merkmalen? – Die Logik scheint mir nur schwer nachvollziehbar …

      obj_help[i].addEventListener('click', function (event) {

Jetzt ist es passiert! Du hast einem img–Element, das (ohne usemap–Attribut) kein interaktiver Inhalt ist, einen click–Handler zugewiesen. Damit ist dein Hilfetext für Seitenbesucher die auf Tastaturbedienbarkeit angewiesen sind nicht erreichbar. Das ist ziemlicher Mist!

<button type="button" class="help">
    <img id="werbung" src="img/icon_info.png" alt="Hilfe"/>
</button>

Für Aktionen auf derselben Seite, wie das Anzeigen eines Hilfetexts, sind buttons da. Die können ohne weiteres Zutun auch per Tastatur (und gegebenenfalls durch andere Eingabegeräte) ausgewählt und aktiviert werden; Ein zugehöriges Bild kann als Elementinhalt notiert oder über CSS eingebunden werden.

Viele Grüße,

Orlok