stopPropagation nicht verstanden?
bearbeitet von OrlokHallo Linuchs
Ich habe noch nicht so ganz durchschaut was du hier zusammenbaust, aber so richtig gut schaut es nicht aus.
> ~~~html
> <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.
> ~~~js
> var erster = document.getElementsByTagName( "body" )[0].firstChild;
> ~~~
`var erster`{: .language-javascript}? 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`?
~~~JavaScript
// 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`{: .language-javascript} referenzieren.
> ~~~js
> document.body.insertBefore( newDiv, erster );
> ~~~
Na sowas, hier ist dir das mit `document.body`{: .language-javascript} 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.
~~~JavaScript
// 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.
> ~~~js
> 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`{: .language-javascript}, oder besser gleich `const`{: .language-javascript}. – 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.
> ~~~html
> <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.
> ~~~js
> 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. ✔️
> ~~~js
> 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.
~~~JavaScript
for (let i = 0, length = helpers.length; i < length; i++) {
~~~
Wenn du für die Deklaration das Schlüsselwort `let`{: .language-javascript} 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`{: .language-javascript}, ist die Sichtbarkeit immerhin auf den lokalen Scope der Funktion begrenzt.
> ~~~js
> 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 …
> ~~~js, bad
> obj_help[i].addEventListener('click', function (event) {
> ~~~
Jetzt ist es passiert! Du hast einem `img`–Element, das (ohne `usemap`–Attribut) kein [interaktiver Inhalt](https://www.w3.org/TR/2017/REC-html52-20171214/dom.html#interactive-content) ist, einen `click`–Handler zugewiesen. Damit ist dein Hilfetext für Seitenbesucher die auf Tastaturbedienbarkeit angewiesen sind nicht erreichbar. Das ist ziemlicher Mist!
~~~HTML, good
<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 `button`s 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
stopPropagation nicht verstanden?
bearbeitet von OrlokHallo Linuchs
Ich habe noch nicht so ganz durchschaut was du hier zusammenbaust, aber so richtig gut schaut es nicht aus.
> ~~~html
> <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.
> ~~~js
> var erster = document.getElementsByTagName( "body" )[0].firstChild;
> ~~~
`var erster`{: .language-javascript}? 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`?
~~~JavaScript
// 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`{: .language-javascript} referenzieren.
> ~~~js
> document.body.insertBefore( newDiv, erster );
> ~~~
Na sowas, hier ist dir das mit `document.body`{: .language-javascript} 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.
~~~JavaScript
// 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.
> ~~~js
> 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`{: .language-javascript}, oder besser gleich `const`{: .language-javascript}. – 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.
> ~~~html
> <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.
> ~~~js
> 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. ✔️
> ~~~js
> 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.
~~~JavaScript
for (let i = 0, length = helpers.length; i < length; i++) {
~~~
Wenn du für die Deklaration das Schlüsselwort `let`{: .language-javascript} 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`{: .language-javascript}, ist die Sichtbarkeit immerhin auf den lokalen Scope der Funktion begrenzt.
> ~~~js
> 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 …
> ~~~js, bad
> obj_help[i].addEventListener('click', function (event) {
> ~~~
Jetzt ist es passiert! Du hast einem `img`–Element, das (ohne `usemap`–Attribut) kein [interaktiver Inhalt](https://www.w3.org/TR/2017/REC-html52-20171214/dom.html#interactive-content) ist, einen `click`–Handler zugewiesen. Damit ist dein Hilfetext für Seitenbesucher die auf Tastaturbedienbarkeit angewiesen sind nicht erreichbar. Das ist ziemlicher Mist!
Für Aktionen auf derselben Seite, wie das Anzeigen eines Hilfetexts, sind `button`s 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