Javascript vergisst Variable + merkwürdiges Verhalten...
$xNeTworKx
- javascript
Hallo,
Ich will einen onmouseover/out Effekt so darstellen, dass nach der Reihe 5 Bilder schnell nacheinander abgespielt werden. Jetzt bin ich aber auf einige Probleme gestossen:
Hier mal ein Teilcode:
var forum = new Array();
forum[0] = new Image(88,23);
forum[0].src = "pics/forum0.jpg";
forum[1] = new Image(88,23);
forum[1].src = "pics/forum1.jpg";
forum[2] = new Image(88,23);
forum[2].src = "pics/forum2.jpg";
forum[3] = new Image(88,23);
forum[3].src = "pics/forum3.jpg";
forum[4] = new Image(88,23);
forum[4].src = "pics/forum4.jpg";
forum[5] = new Image(88,23);
forum[5].src = "pics/forum5.jpg";
var i = 0;
var j = 5;
function lightimage(bildnummer) {
if (i <= 5) {
document.images[bildnummer].src = forum[i].src;
}
i++;
window.setTimeout("lightimage(bildnummer)",40);
}
function darkimage(bildnummer) {
if (j >= 0) {
document.images[bildnummer].src = forum[j].src;
}
j--;
window.setTimeout("darkimage(bildnummer)",40);
}
Die Javascript Funktion "lightimage" vergisst die Variable "bildnummer" in der Zeile window.setTimeout... aber warum? Wenn ich die Zahl zB 1 einsetze, funktioniert es. Ich brauche aber hier eine Variable, da ich mehrere Links habe, die natürlich verschiedene Bildnummern haben. Wie ich forum[i].src; dynamisch mache, dass dann zB mail[i].src in einer Variable gespeichert ist, die dann statt forum[i].src datsteht, weiß ich jetzt auch noch nicht. Wenn ich lightimage(bildnummer,button) angebe und mir zb die Übergabevariable 'forum' auf button übergeben lasse, funktioniert button[i].src nicht, aber das ist ein anderes Problem.
Das nächste Problem, das ich nicht verstehe ist, wenn ich den mouseover Effekt auslöse und mit der Maus wieder vom Link weggehe, funktioniert das ganze einmal und zwar im IE. Opera und Mozilla spielen die Animation auch nur einmal ab, und zwar auch nur dann, wenn ich ganz vorsichtig auf den Link fahre. Wenn ich das nicht vorsichtig tue, wird der onmouseout Effekt sofort nach dem onmouseover Effekt abgespielt, obwohl ich mit der Maus den LInk noch nicht verlassen habe. Was kann da sein?
$xNeTworKx.
Hallo $xNeTworKx.
zum Teilproblem 1:
probier mal
window.setTimeout("darkimage("+bildnummer+")",40);
Gruss Olaf
Moin!
window.setTimeout("lightimage(bildnummer)",40);
Die Javascript Funktion "lightimage" vergisst die Variable "bildnummer" in der Zeile window.setTimeout... aber warum?
Der Befehl, der nach 40 Millisekunden ausgeführt wird, lautet:
lightimage(bildnummer);
Und da bildnummer keine globale Variable ist, sondern undefiniert, hast du hier ein Problem.
Besser: Übergib direkt die Bildnummer:
window.setTimeout("lightimage("+bildnummer+")",40);
Der dann ausgeführte Befehl wird ungefähr so lauten:
lightimage(1);
Und das ist genau, was du brauchst, denn so wird die Funktion ja wohl erstmalig auch aufgerufen.
Wie ich forum[i].src; dynamisch mache, dass dann zB mail[i].src in einer Variable gespeichert ist, die dann statt forum[i].src datsteht, weiß ich jetzt auch noch nicht.
Für sowas sind zweidimensionale Arrays ganz super.
anibilder = new Array();
anibilder[0] = new Array();
anibilder[0][0] = new Image();
...
Dann stehen deine Bilder nicht mehr in forum[0-5], sondern in anibilder[0][0-5].
Die Auswahl, welche Animation genommen werden soll, muß natürlich der Funktion übergeben werden.
Das nächste Problem, das ich nicht verstehe ist, wenn ich den mouseover Effekt auslöse und mit der Maus wieder vom Link weggehe, funktioniert das ganze einmal und zwar im IE. Opera und Mozilla spielen die Animation auch nur einmal ab, und zwar auch nur dann, wenn ich ganz vorsichtig auf den Link fahre. Wenn ich das nicht vorsichtig tue, wird der onmouseout Effekt sofort nach dem onmouseover Effekt abgespielt, obwohl ich mit der Maus den LInk noch nicht verlassen habe. Was kann da sein?
Die Browser sind teilweise ein wenig seltsam, was die Erzeugung von Events angeht. Da ist man am besten bedient, wenn man die Events nicht sofort für eine Aktion heranzieht, sondern erstmal etwas abwartet und dann tut - wenn man noch soll.
Das bedeutet aber wieder Arbeiten mit setTimeout, außerdem müssen die durch Events erzeugten Wünsche irgendwie global zwischengespeichert werden und dürfen sich nicht gegenseitig überschreiben.
Du mußt verhindern, dass sich beispielsweise zwei Animationen gegenseitig in die Quere kommen. Wenn ein mouseover durch ein nachfolgendes mouseout unterbrochen wird, mußt du das mouseover abbrechen und stattdessen das mouseout abspielen. Allerdings wäre es für die Animation blöd, wenn das mouseover nur bis zur Mitte gekommen ist, mit dem mouseout bei letzten Bild zu beginnen. Du mußt also im Prinzip für jeden Button eine (am besten globale) Variable haben, welches Bild derzeit angezeigt wird. Wenn du noch mouseover machen sollst, wird die Bildzahl inkrementiert, wenn du mouseout machen sollst, wird sie dekrementiert, solange bis das erste oder letzte Bild erreich ist.
Deine Funktion läuft auch deshalb nur einmal, weil du zwar globale Variablen i und j zum Zählen der Bilder verwendest, diese aber jeweils nur erhöht (i) oder erniedrigt (j) werden - und es dann bleiben. Das heißt: Nach dem ersten mouseover ist i auf 5 - entsprechend wird das zweite Mouseover direkt das letzte Bild aufrufen, ohne es zu animieren. Beim Mouseout ist das genauso.
Ich denke, du hast noch einiges zu tun. Insbesondere die in den Browsern ziemlich wackligen Events dürften dir einiges Kopfzerbrechen bereiten. Du solltest dir dafür irgendeine Art von Debugging-Routine schreiben, dir dir (mittels alert() oder auch durch document.write()-Ausgabe in ein Popup) anzeigen, welche Events gerade gefeuert haben. Oft ist es so, dass durch Änderungen an der dargestellten Seite (z.B. durch Ändern des Bildes unter dem Mauszeiger) zuerst mouseout feuert (weil das alte Bild, wenn es nicht mehr gezeigt wird, ja auch nicht mehr unter dem Mauszeiger ist), und dann sofort mouseover (weil das neue Bild unter dem Mauszeiger ist).
- Sven Rautenberg
Hallo Sven,
window.setTimeout("lightimage("+bildnummer+")",40);
Ok, das hat mal geholfen =)
[...] zweidimensionale Arrays [...]
Ok, das werde ich dann ausprobieren, wenn mal das eine funktioniert.
Das Problem mit den Events wäre eigentlich nicht so schlimm, wenn sich diese in die Quere kommen, weil die Animation sowieso sehr schnell abgespielt wird, wodurch es dann eigentlich nicht auffällt, wenn die andere Animation die 1. stoppt.
Deine Funktion läuft auch deshalb nur einmal, weil du zwar globale Variablen i und j zum Zählen der Bilder verwendest, diese aber jeweils nur erhöht (i) oder erniedrigt (j) werden - und es dann bleiben. Das heißt: Nach dem ersten mouseover ist i auf 5 - entsprechend wird das zweite Mouseover direkt das letzte Bild aufrufen, ohne es zu animieren. Beim Mouseout ist das genauso.
Ja, das wäre eigentlich mein Hauptproblem. Wie kann ich i wieder auf 0 setzen? Man könnte meinen, if (i == 5) i = 0; aber da beginnt dann die Animation zu flackern. Mit einem break habe ich auch noch keine Erfolge gehabt, da mir Javascript bei so einer Funktion
function lightimage(bildnummer) {
if (i <= 5) {
document.images[bildnummer].src = forum[i].src;
window.setTimeout("lightimage("+bildnummer+")",40);
}
i++;
if (i > 5) {
i = 0;
break;
}
}
eine Meldung ausgibt, dass es ein Objekt erwarte (in der Zeile in der HTML Datei, in der der onmouseover Effekt ausgelöst wird).
Ich hoffe du kannst mir nochmal helfen.
$xNeTworKx.
Moin!
Deine Funktion läuft auch deshalb nur einmal, weil du zwar globale Variablen i und j zum Zählen der Bilder verwendest, diese aber jeweils nur erhöht (i) oder erniedrigt (j) werden - und es dann bleiben. Das heißt: Nach dem ersten mouseover ist i auf 5 - entsprechend wird das zweite Mouseover direkt das letzte Bild aufrufen, ohne es zu animieren. Beim Mouseout ist das genauso.
Ja, das wäre eigentlich mein Hauptproblem. Wie kann ich i wieder auf 0 setzen? Man könnte meinen, if (i == 5) i = 0; aber da beginnt dann die Animation zu flackern.
Dein bisheriger Ansatz ist schlecht. Du brauchst für jeden Button eine Variable, die die Nummer der angezeigten Bildes enthält. Also jeder Button kriegt sein "i" - welches auch als "j" benutzt wird fürs Abwärtszählen.
Außerdem brauchst du je Button noch eine Variable, die mit true oder false angibt, ob aufwärts oder abwärts gezählt werden soll, also ob mouseover oder mouseout erfolgt.
Mit diesen Variablen kannst du dann eine _einzige_ Funktion füttern, die dir die Animation realisiert. Diese Funktion kriegt gesagt, welcher Button zu animieren ist, liest die zwei globalen Variablen des Buttons aus und reagiert entsprechend.
onmouseover und onmouseout setzen nur die Richtungsvariable (auf true oder false) und initialisieren die Animationsfunktion. Die Animation selbst läuft aber von den Events her vollkommen unabhängig. Das hat den Vorteil, dass du auch während der Animation (in der _einen_ Funktion) die Animationsrichtung einfach durch setzen der Richtungsvariablen umdrehen kannst. Die Animation wird dann einfach sofort in die andere Richtung gehen.
Das Initialisieren der Animationsfunktion ist im Prinzip so zu lösen, dass du (wieder in einer globalen Variablen) speicherst, ob gerade eine Animationsfunktion für einen Button läuft. Je Button darf nur eine Animation laufen. Wenn eine Animation läuft, reicht das Ändern der globalen Richtungsvariablen, um die neue Animation abzuspielen. Wenn keine Animation läuft, muß sie gestartet werden.
Man könnte diese Initialisierung auch damit überflüssig machen, das gleich beim Seitenladen eine sich endlos aufrufende Funktion gestartet wird, die regelmäßig schaut, ob irgendwas animiert werden muß - das würde aber heftig Performance fressen, auch wenn gar nichts los ist, und ist deshalb nicht ratsam.
Nochmal zum Mitschreiben:
Zerlege deine Funktionen in drei Stücke:
1. Globale Variablen, die die Zustände aller Animationen repräsentieren und auf die sowohl die Animationsfunktion als auch die mouseover/out-Events zugreifen.
2. Eine Animationsfunktion, die nur dafür sorgt, dass
a) das nächste Bild angezeigt wird, entsprechend der globalen Variablen "Bildnr" und "Richtung" des jeweiligen Buttons, und
b) die sich selbst wieder aufruft, um die Animation fortzusetzen, sofern die Animation den Endpunkt noch nicht erreicht hat. Andernfalls muß sie (durch Rücksetzen der globalen Variablen) melden, dass die Animation beendet ist.
3. Eine Animations-Initialisierung, die die Animation eines Buttons anstößt, sofern dieser Button derzeit nicht animiert wird, und diesen Zustand in der globalen Variablen vermerkt.
Das klingt auf den ersten Blick erstmal furchtbar kompliziert, aber du erleichterst dir damit viele Dinge, wenn du so ein Konstrukt erstmal sauber aufgebaut hast. Vielleicht willst du demnächst als Animation nicht Bilder austauschen, sondern z.B. Layer durch die Gegend schieben - das geht grundsätzlich genauso, wie Bilder austauschen. Du bastelst dir also jetzt ein Grundgerüst, das du später immer wieder einsetzen kannst, wenn etwas zu animieren ist.
- Sven Rautenberg
Hallo Sven,
danke für die ausführliche Erklärung. Ich muss das Ganze erst mal verdauen =).
$xNeTworKx.