stopPropagation nicht verstanden?
Linuchs
- javascript
Moin,
wenn ich auf ein Info-Symbol klicke, soll das Klick-Event die Info-Anzeige per Ajax vom Server holen und anzeigen, aber im DOM der Seite nicht weitergemeldet werden. Deshalb versehe ich diese (i)
Symbole mit der Bitte stopPropagation
.
Auf der Seite http://remso.eu/ habe ich das rot umrandete Werbe-div in den <a>
tag eingeschlossen. Egal wohin man klickt, der Link führt zu den Seiten des Gasthauses.
Mit einer Ausnahme: Das Hilfe-Symbol (i)
unten links innerhalb des Werbe-div soll bei Klick nur einen erklärenden Text einblenden, aber nicht zum Gasthaus verlinken.
Der Link wird trotz stopPropagation ausgeführt. Warum?
<img id="werbung" class="help" src="img/icon_info.png" alt="?" title="Info" />
window.addEventListener('DOMContentLoaded', function ( ) {
//alert( "hier ajax_getHelptext.js" );
// Textfeld einrichten
var erster = document.getElementsByTagName( "body" )[0].firstChild;
var newDiv = document.createElement("div");
newDiv.id = "helptext";
document.body.insertBefore( newDiv, erster );
/* *************************************************
*
* HELP-Icons/Buchstaben anschliessen
*
************************************************* */
obj_help = document.getElementsByClassName( "help" );
for ( i=0; i<obj_help.length; i++ ) {
if ( obj_help[i].id ) {
obj_help[i].addEventListener('click', function (event) {
getHelptextXY( bia_domain, bia_owner, bia_kw, bia_ll, this.id, bia_lg, event.clientX, event.clientY );
event.stopPropagation(); // Klick-Event verbirgt sonst den helptext wieder
});
}
}
});
Gruß, Linuchs
Meinten Sie vielleicht e.preventDefault() für das abgefangene Klickevent.
hallo
Meinten Sie vielleicht e.preventDefault() für das abgefangene Klickevent.
das müsste er aber auf dem a-Element registriern, was er wohl nicht will.
Die Antwort heisst: Verschachtle keine interaktiven Elemente.
Die Antwort heisst: Verschachtle keine interaktiven Elemente.
Mein erster Versuch war, diese Info hinter dem <a>
tag per margin-top:-2em
in den Werbe-div zu schmuggeln, doch er verschwand in der dritten Dimension (z-index) unter dem div und ward nicht mehr gesehen.
Einer Information die kein position:absolute
hat, kann man ja auch keinen wirksamen z-index
mitgeben.
hallo
Einer Information die kein
position:absolute
hat, kann man ja auch keinen wirksamenz-index
mitgeben.
doch!
doch!
danke, es funktioniert mit position:relative;margin-top:-3em;z-index:2;
Gruß, Linuchs
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 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