[JS] eventlistener lassen sich nicht entfernen

nietaL

NGBler
Registriert
8 Sep. 2013
Beiträge
231
Ort
Exilgullianer
Mit einem Doppelklick auf ein Bild (HTML Z.5) wird ein Zoom ausgeführt und ein eventlistener hinzugefügt (JS Z.52), der darauf achtet, ob eine Pfeiltaste gedrückt wird, um das gezoomte Bild zu verschieben (JS Z.56).

Wird wieder doppelt geklickt, soll der eventlistener wieder gelöscht werden (JS Z. 35).

Der Ein- und Auszoomen sowie das Umhersliden auf der Karte funktioniert, wie es soll. Leider entfernt er nicht den Eventlistener und jedesmal wenn ich einmal hineinzoome, wird ein weiterer Listener hinzugefügt und somit auch jede Pfeiltaste 2, 3, 4, 5mal ausgewertet. Somit wird bei jedem Zoomen das Sliden schneller.

Könnt ihr mir sagen, warum er den listener nicht entfernt?

Austesten könnt ihr es hier:

Liebe Grüße!

PS: Bitte nicht über die Unordnung schimpfen. Es ist ein Sandkasten.




[src=javascript]
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script language="jscript" type="text/javascript">


function mouse_pos()
{
$("#karte").mousemove(function(event){
relX = event.pageX - $("#karte").offset().left;
relY = event.pageY - $("#karte").offset().top;
});
}

function zoom()
{

gebiete = ['gebiet1'];


if(document.getElementById('karteninhalt').style.width == '3388px')
{
document.getElementById('karteninhalt').style.top = '0px';
document.getElementById('karteninhalt').style.left = '0px';
document.getElementById('karteninhalt').style.width = '1150px';
document.getElementById('karteninhalt').style.height = '950px';

gebiete.forEach(function(element)
{
document.getElementById(element).style.width = (parseInt(document.getElementById(element).style.width.split('px')) / 2)+'px';
document.getElementById(element).style.height = (parseInt(document.getElementById(element).style.height.split('px')) / 2)+'px';
document.getElementById(element).style.top = (parseInt(document.getElementById(element).style.top.split('px')) / 2)+'px';
document.getElementById(element).style.left = (parseInt(document.getElementById(element).style.left.split('px')) / 2)+'px';
});

document.removeEventListener("keydown", slide);
}
else
{
document.getElementById('karteninhalt').style.top = -(relY*2)+'px';
document.getElementById('karteninhalt').style.left = -(relX*2)+'px';
document.getElementById('karteninhalt').style.width = '3388px';
document.getElementById('karteninhalt').style.height = '2799px';

gebiete.forEach(function(element)
{
document.getElementById(element).style.width = (parseInt(document.getElementById(element).style.width.split('px')) * 2)+'px';
document.getElementById(element).style.height = (parseInt(document.getElementById(element).style.height.split('px')) * 2)+'px';
document.getElementById(element).style.top = (parseInt(document.getElementById(element).style.top.split('px')) * 2)+'px';
document.getElementById(element).style.left = (parseInt(document.getElementById(element).style.left.split('px')) * 2)+'px';
});

document.addEventListener("keydown", slide);
}


function slide (event)
{
event.preventDefault();

if (event.keyCode == 39 && document.getElementById('karteninhalt').style.width == '3388px')
{
var bild_left_srg = document.getElementById('karteninhalt').style.left;
var bild_left_val = bild_left_srg.split('px');
var bild_left_new = parseInt(bild_left_val) - 300;
if (bild_left_new < -2250) {bild_left_new = -2250;}
document.getElementById('karteninhalt').style.left = bild_left_new + 'px';
}
if (event.keyCode == 37 && document.getElementById('karteninhalt').style.width == '3388px')
{
var bild_left_srg = document.getElementById('karteninhalt').style.left;
var bild_left_val = bild_left_srg.split('px');
var bild_left_new = parseInt(bild_left_val) + 300;
if (bild_left_new > 0) {bild_left_new = 0;}
document.getElementById('karteninhalt').style.left = bild_left_new + 'px';
}
if (event.keyCode == 38 && document.getElementById('karteninhalt').style.width == '3388px')
{
var bild_top_srg = document.getElementById('karteninhalt').style.top;
var bild_top_val = bild_top_srg.split('px');
var bild_top_new = parseInt(bild_top_val) + 300;
if (bild_top_new > 0) {bild_top_new = 0;}
document.getElementById('karteninhalt').style.top = bild_top_new + 'px';
}
if (event.keyCode == 40 && document.getElementById('karteninhalt').style.width == '3388px')
{
var bild_top_srg = document.getElementById('karteninhalt').style.top;
var bild_top_val = bild_top_srg.split('px');
var bild_top_new = parseInt(bild_top_val) - 300;
if (bild_top_new < -1850) {bild_top_new = -1850;}
document.getElementById('karteninhalt').style.top = bild_top_new + 'px';
}
};
}




</script>
[/src]


[src=html4strict]

<body background="tisch_6.jpg">

<div id="karte" onMouseOver="mouse_pos();" onDblClick="zoom();" style="position: absolute; width: 1150px; height: 950px; z-index: 3; overflow: hidden; left: 396px; top: 168px; transform: rotate(-3deg);">



<div id="rahmen" style="position:absolute; background-image:url(rahmen.png); height:950px; width: 1150px; left:0px; top:0px; background-size: contain; z-index:3;"></div>
<div id="struktur" style="position:absolute; background-image:url(struktur.png); height:874px; width: 1074px; left:38px; top:38px; background-size: contain; z-index:2; opacity:0.2"></div>


<div id="karteninhalt" style="position:absolute; width: 1150px; height: 950px; left:0px; top:0px; transition: 0.7s; z-index:1;">



<div id="gebiet1" style="position: absolute; left: 314px; top: 252px; width: 59px; height: 50px; transition: 0.7s; background-image:url(tile.png); background-size: contain; background-repeat: no-repeat; "></div>

<img src="karte_hg.jpg" width="100%" height="100%" />


</div>
</div>

[/src]
 
Das sieht wirklich top aus, aber dein Code... :D

Mal drei Vorschläge, vorzugsweise den letzten?

[src=javascript]
// Simple

function zoom() {
// Sollte nicht fehlschlagen wenn nichts gesetzt ist.
document.removeEventListener("keydown", slide);

if (condition == true) {
// Und wieder neu binden
document.addEventListener("keydown", slide);

// Code
}
}

// ODER globale Variable

var isZoomActive = false;

function zoom() {
isZoomActive = !isZoomActive;
isZoomActive ? document.addEventListener("keydown", slide) : document.removeEventListener("keydown", slide);
}

// ODER dataset, data Attribute auf dem Clickziel, bitte zoom(evt/e/evt/ziel....) und das "ziel".target anpassen, verwenden!

function zoom(evt) {
if (evt.target.dataset.zoomActive) {
evt.target.dataset.zoomActive = false;
document.removeEventListener("keydown", slide);
} else {
evt.target.dataset.zoomActive = true;
document.addEventListener("keydown", slide);
}
}[/src]
 
Zuletzt bearbeitet:
  • Thread Starter Thread Starter
  • #3
Hey, danke für deine Antwort. Den Kommentar zum Code verzeihe ich dir :D

Ich habe jetzt einfach mal schnell deine ersten beiden Lösungen ausprobiert. Sie zeigen alle dasselbe verhalten. Es werden endlos eventhandler hinzugefügt, aber keine gelöscht. Ich werde noch wahnsinnig.
Die Debug-Konsole bei Firefox zeigt das auch sehr schön an.

* Strg + Umschalt + S
* Linker Reiter "Inspektor"
* Klick auf das kleine [ev]-Symbol neben dem <html>-Tag

Mit jedem Zoom kommt ein keydown-event dazu.

Vielleicht schaust du mal direkt in den Quelltext hinein? Ich bin mit meinem Latein am Ende. So kompliziert ist der Aufbau ja nun nicht. :m


*edit*

Habe es jetzt hiermit gelöst:
[src=javascript]
document.onkeydown = function(event) {
if (event.keyCode == 38) {
alert("Los geht's");
}
}[/src]

Den Unterschied zwischen dem und nem eventhandler verstehe ich zugegebenermaßen nicht. Zumindest funktioniert dieser einfachere Code jetzt :cool:
 
Zuletzt bearbeitet:
Das Problem ist, dass du die Funktion [kw]slide[/kw] innerhalb der Funktion [kw]zoom[/kw] definiert hast - bei jedem Aufruf von zoom() wird eine neue "Funktions-Instanz" erstellt. Das muss so sein, weil du in der inneren Funktion ja Variablen oder Paramter aus der äußeren Funktion benutzen könntest. Das heißt, dass jedes [kw]addEventListener[/kw] und [kw]removeEventListener[/kw] eine neue, einzigartige Funktion bekommt, die zwar das gleiche macht wie alle andern Funktions-Instanzen auch, aber eben nicht gleich ist. removeEventListener versucht also eine Funktion zu entfernen, die er noch nie gesehen hat, und scheitert dabei (lässt alle "anderen" Funktionen aber intakt).

Beispiel:
[src=javascript]function outer(){
function f(){
return 0;
}
return f;
}

outer == outer // => true (weil 2x die gleiche Instanz)
outer() == outer() // => false (jeder Aufruf von outer() erzeugt ein neues f)
var f = outer(); f == f // => true (2x die gleiche Instanz)[/src]

tl;dr: Einfachste Lösung wäre es, deine [kw]slide[/kw]-Funktion einfach außerhalb von [kw]zoom[/kw] zu deklarieren.

Ja, Javascript hat ein ziemlich interessantes "Scoping" (Verhalten bei geschachtelten Funktionen). Lohnt sich aber, sich da mal etwas reinzulesen...
 
Das Problem ist, dass du die Funktion [kw]slide[/kw] innerhalb der Funktion [kw]zoom[/kw] definiert hast - [....]

Uh, das hab ich gar nicht gesehen..., jetzt wo du es sagst, sehe ich es auch, bin davon ausgegangen die Funktion ist nicht geschachtelt, war wohl zu früh. :D

Hätte es mal in nen Editor kopieren sollen, dann wäre mir das vielleicht auch aufgefallen... :unknown:

Aber die Erklärung ist top! :)
 
Zurück
Oben