Toon posts:

[javascript] timers en het attachen van eventfunctions

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik weet niet precies hoe ik mn verhaal duidelijk moet maken, maar hoop dat met de tekst hieronder wat te doen is :)

In de database heb ik een treemenu staan die ik natuurlijk als html output richting de gebruiker wil gooien. Nu moet dat menu submenu's kunnen bevatten of moet er een bewerking middels een event op plaats gaan vinden (zoals een fade oid). Ik kan dat op twee manieren doen. Ik maak in javascript een object die mn menu en menuitems kan bevatten en creeër renderfunctionaliteit die mn menu gaat weergeven met daaraan al mn mouseovers, mouseouts en onclicks. Maar dat wil ik niet. De zoekmachine heeft voor zover ik weet moeite met menu's in javascript die dynamisch gerenderd wordt. Dus wil ik het volgende: ik render in mn webpagina serverside mn menu in html zonder event attributen. Waarom niet? Stel ik wil een tree van 1 level diep presenteren en op elk menuitem wil ik een fade in en out zetten, dan wil ik wel dat ze a-synchroon werken. Ze moeten niets met elkaar van doen hebben. Om dat te bereiken zal ik eigenlijk voor elk menuitem waardes als de opacity op dat moment moeten bijhouden, een eigen timer geven etc etc. Nu had ik daarvoor het volgende idee. Ik genereer serverside zoals ik eerder zei mn html zodat de zoekmachine goed door mn website heen kan wandelen en ik zorg dat clientside mn hele menustructuur in een javascript object is opgeslagen. Ik gebruik onderstaande class om clientside mn menu hiërarchisch in op te slaan.

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function MenuItem (id, name)
{
    this.id            = id;
    this.name          = name;
    this.children      = new Array();
    
    this.opacity      = null;
    this.opacitystart = null;
    this.opacityend   = null;
    this.opacitystep  = null;
    this.opacityspeed = null;
    this.outfaded     = null;
    
    this.timer        = null;
    
    this.SetOpacityValues = function (opacitystart, opacityend, opacitystep, opacityspeed)
    {
        this.opacity      = opacitystart;
        
        this.opacitystart = opacitystart;
        this.opacityend   = opacityend;
        this.opacitystep  = opacitystep;
        this.opacityspeed = opacityspeed;
        
        this.outfaded       = false;            
    }
    
    this.AddChild = function (menuitem)
    {
        this.children[this.children.length] = menuitem;
    }
    
    this.Fader = function ()
    {
        alert ('hij fade :-)');
    }
}


Nu had ik het idee dus om middels een initialize function in een lusje een functie voor de verschillende events aan de html objecten (mn serverside gegenereerde html) te koppelen.

JavaScript:
1
2
3
4
5
for (var i = 0; i < this.menuitems.children.length; i++)
{
    document.getElementById(this.menuitems.children[i].id).onmouseover = this.menuitems.children[i].Fader;
    document.getElementById(this.menuitems.children[i].id).onmouseout = this.menuitems.children[i].Fader;
}


Op deze manier hoopte ik in mn Fader functie gebruik te kunnen maken van this.timer zodat ik altijd een unieke timer bij kon houden per menuitem, per menuitem mn fade snelheid in te stellen etc etc... Maar helaas dit ging mij om de een of andere manier niet lukken. Met een work arround (lees: een hele andere manier dan dat ik wilde) heb ik een werkende versie gekregen (staat hier). Maar omdat ik met die workarround eigenlijk niet bereikt heb wat ik voor ogen heb, ben ik benieuwd of iemand mij uit de brand kan helpen! De manier van werken lijkt me veel mogelijkheden geven en hoop dat men mij meer tips e.d. kan geven over het gebruik van timers in zulke gevallen en het attachen van events!

Verwijderd

Topicstarter
Niemand een idee??? Als mn verhaal of mn bedoeling te vaag is hoor ik dat ook graag. Dat zelfde geldt voor als mijn hele idee nergens op slaat en dat eenvoudiger op een andere manier kan oplossen...

Verwijderd

Wat is nou precies je vraag? :P Ik zie geen problemen met de opzet die je hier presenteert.Leg eerst eens uit wat er nou zo anders is aan de 'workaround'. Ik kan je wel al vertellen dat als je met een geneste list-structuur werkt, de CSS-opacity van de parent wordt overgenomen door de kinderen. Veroorzaakt dat je probleem?

Voor meer info over het gebruik van OO in JavaScript kan ik je altijd Clay's tutorial aanbevelen en dan speciaal het stuk over Timers.

Verwijderd

Topicstarter
Nou de benadering van de functie this.Fader ging me wel lukken, maar de bijbehorende waardes binnen het object waarbij this.Fader bij zou moeten horen waren weg! Blijkbaar legtie de referentie niet naar het juiste object o.i.d. en doe ik ergens dus iets fout... Mijn vraag was dus: is deze opzet zo raar en zo niet: hoe zorg ik ervoor dat ik een event laat verwijzen naar de methode van zijn object met de bijbehorende properties, want dat gaat bij mij op de een of andere manier fout.

Ik zal Clay's tutorial eens rustig doornemen, bedankt!

Verwijderd

Volgens mij wil jij het observer pattern implementeren. Je registreert dan je targets bij een listener (de observer) die een notify krijgt en de targets aanroept. Ik heb zoiets ook in mijn web interface zitten om bij een wijziging van selectie in de interface automatisch alle commands erop te laten reageren.

Ik zal even een voorbeeld maken ..

Verwijderd

Ik heb even een heel vereenvoudigd voorbeeld gemaakt die aantoond wat er gebeurt.

Stel je hebt dus een menu object ( function menu(){return this;} ) dan kun je die bij de observer aanmelden. Zodra op die observer de notify method wordt bij elk registered element ook de notify aangeroepen. Op basis van die notify per registered element kun je vervolgens bepalen wat daaropvolgende acties zijn.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<script type="text/javascript">
function observer(name){
  this.name = name;
  this.listeners = [];
}
observer.prototype {
    
    register : function(object){
          this.listeners.push(object);
    },
    
    notify : function(){
        var i = this.listeners.length;while(i--){
            this.listeners[i].notify(); 
        }
    }
}
</script>

En bijvoorbeeld een object wat je registered:

<script type="text/javascript">
function Car(){
  this.pedalState = 'up';
  this.onChangeHandler = null;  
}
Car.prototype.notify = function(){
  this.onChangeHandler();
}


var myObserver = new observer('mijn observer');
var myCar = new Car();
myCar.onChangeHandler = function(){
  if(this.pedalState == 'down'){
     this.drive();
  }else{
     this.stop();
  }
}

myObserver.register(myCar);

</script>



Nu heeft myCar een handler gekregen die reageert op de notify van de observer. Als het pedaal ingetrapt is moet hij rijden, anders stoppen. Nu moet je alleen nog de status van het pedaal wijzigen, en dit is iets wat je bijvoorbeeld uitvoert als je een button aanklikt.

PHP:
1
2
3
4
5
6
<script type="text/javascript">
function pressGasPedal(){
  myCar.pedalState = 'down';
  myObserver.notify();
}
</script>

[ Voor 17% gewijzigd door Verwijderd op 07-03-2005 09:50 ]


Verwijderd

Of wat ook kan is dat je simpelweg nog een scope moet aanmaken :+ Omdat anders this naar het window object verwijst en niet naar je doelobject.

var self = this;
setTimeout(function(self.doeIets()),1000);

ipv de foute benadering:

setTimeout(function(this.doeIets()),1000);

  • Clay
  • Registratie: Oktober 1999
  • Laatst online: 25-02 11:17

Clay

cookie erbij?

Blues
Voor meer info over het gebruik van OO in JavaScript kan ik je altijd Clay's tutorial aanbevelen en dan speciaal het stuk over Timers.
Sooterd
Ik zal Clay's tutorial eens rustig doornemen, bedankt!
Misschien zou ik de tut ook eens uit kunnen breiden met een stuk over events :) 't gaat dan natuurlijk wel subjectiever worden aangezien dat op meerdere manieren te doen is, maar op zich is er genoeg algemeens over te vertellen :P

Instagram | Flickr | "Let my music become battle cries" - Frédéric Chopin


Verwijderd

Topicstarter
Thnx voor de uitgebreide toelichting van observer pattern! Lost niet echt mn vraag op (voor zover ik het allemaal begrijp) hoewel ik wel weer mogelijk zie in deze manier van werken! Het ging mij met name om de koppeling tussen mn HTML object (om het zo maar te zeggen) waar ik middels JavaScript dynamisch functies hang aan mn onmousover, onmousout en onclick. Die functie die ik er aan koppel zou eigenlijk de methode moeten zijn van het menuitem, zodat ik in JavaScript bij de eigenschappen kan die ik in JS heb gedefinieerd...

In de tutorial van Clay staat iig al goed uitgelegt hoe ik met timers om kan gaan zodat ik zelf een methode weer kan aanroep na een bepaalde tijd. Dat moet dus wel gaan lukken nu...

@Clay: dat zou niet verkeerd zijn, er zijn vast meer mensen die met zulk soort situaties zitten..

[ Voor 3% gewijzigd door Verwijderd op 07-03-2005 10:05 ]


Verwijderd

Het punt is ook een beetje dat er gewoon zoveel mogelijk is in Javascript qua eventhandling en dat er ook de nodige valkuilen zitten (lees veel valkuilen) mbt memory management. Dan ben je eigenlijk ook direct weer verplicht om daar een stuk aan te wijden met dispose methods, gebruik van delete, null, dom references, anonymous eventhandlers,cyclic references etc.

[ Voor 4% gewijzigd door Verwijderd op 07-03-2005 10:05 ]


  • BtM909
  • Registratie: Juni 2000
  • Niet online

BtM909

Watch out Guys...

Ace of Base vs Charli XCX - All That She Boom Claps (RMT) | Clean Bandit vs Galantis - I'd Rather Be You (RMT)
You've moved up on my notch-list. You have 1 notch
I have a black belt in Kung Flu.


Verwijderd

Je bedoelt zoiets?

function menu(){

}

menu.prototype.show ..
menu.prototype.hide ..
menu.prototype.fadeIn
menu.prototype.fadeOut
menu.prototype.delete

etc? :) Dus echt het OO gedeelte? Dan lijkt me Clays tut het beste startpunt, je hebt dat ding sneller doorgelezen dan wij het hebben uitgelegd. :)

Dan ben je in staat om bijv. dergelijke constructies te maken:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script type="text/javascript">
function demo(label){
  this.label = label;
}
demo.prototype {
    draw : function(){
        this.elementje = document.createElement('DIV');
        this.elementje.appendChild(document.createTextNode(this.label));
        document.body.appendChild(this.elementje);  
    },
    show : function(){
       this.elementje.style.display = 'block';
    },
    hide : function(){
       this.elementje.style.display = 'none';
    },
    delayedShow : function(){
       var self = this;
       window.setTimeout(function(){self.show()},1000);
    },
    delayedHide : function(){
       var self = this;
       window.setTimeout(function(){self.hide()},1000);
    }
}
</script>

[ Voor 49% gewijzigd door Verwijderd op 07-03-2005 10:31 ]


Verwijderd

Topicstarter
Daar gaat het me ook nog niet helemaal om :)

Ik vind het wat lastig om het uit te leggen... Dus heb ik een voorbeeldje gemaakt zodat hopelijk duidelijk wordt wat bij mij niet lukt.

HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
<html>

<head>
    <title>Object Oriented JavaScript</title>
</head>

    <script>
        
        function Initialize (menuitems)
        {
            for (var i = 0; i < menuitems.children.length; i++)
            {
                document.getElementById(menuitems.children[i].id).onclick = menuitems.children[i].Fader;
            }
        }
        
        function MenuItem (id, name)
        {
            this.id           = id;
            this.name         = name;
            this.children     = new Array();
            
            this.opacity      = null;
            this.opacitystart = null;
            this.opacityend   = null;
            this.opacitystep  = null;
            this.opacityspeed = null;
            this.state      = true;
            
            this.timer        = null;
        }
        
            MenuItem.prototype.SetOpacityValues = function (opacitystart, opacityend, opacitystep, opacityspeed)
            {
                this.opacity      = opacitystart;
                
                this.opacitystart = opacitystart;
                this.opacityend   = opacityend;
                this.opacitystep  = opacitystep;
                this.opacityspeed = opacityspeed;
                
                this.outfaded     = false;            
            }
            
            MenuItem.prototype.AddChild = function (menuitem)
            {
                this.children[this.children.length] = menuitem;
            }
            
            MenuItem.prototype.Fader = function ()
            {
                alert (this.opacity);
            }
            
    </script>

<body>

    <ul>
        <li><a id="a" href="#">a</a></li>
        <li><a id="b" href="#">b</a></li>
        <li><a id="c" href="#">c</a></li>
        <li><a id="d" href="#">d</a></li>
    </ul>

    <script type="text/javascript">
            
        var opacitystart = 100;
        var opacityend   =  40;
        var opacitystep  =   4;
        var opacityspeed =  40;
        
        var menu;
        var menuitem;
        var submenuitem;
        
        menuitem = new MenuItem ('root', 'root');
            
            submenuitem = new MenuItem ('a', 'item a');
            submenuitem.SetOpacityValues (opacitystart, opacityend, opacitystep, opacityspeed);
            menuitem.AddChild (submenuitem);
            
            submenuitem = new MenuItem ('b', 'item b');
            submenuitem.SetOpacityValues (opacitystart, opacityend, opacitystep, opacityspeed);
            menuitem.AddChild (submenuitem);
            
            submenuitem = new MenuItem ('c', 'item c');
            submenuitem.SetOpacityValues (opacitystart, opacityend, opacitystep, opacityspeed);
            menuitem.AddChild (submenuitem);
            
            submenuitem = new MenuItem ('d', 'item d');
            submenuitem.SetOpacityValues (opacitystart, opacityend, opacitystep, opacityspeed);
            menuitem.AddChild (submenuitem);
        
        Initialize(menuitem);

    </script>

</body>

</html>


Regel 17 t/m 53 staat mn menuitem object met de daarbijbehorende properties en methodes. Levert wat dat betreft geen enkel probleem op. Ik kan daar ook een render functie aan hangen om het menu te genereren. Is ook geen probleem...

Regel 59 t/m 63 staat mn serverside geparste html. op deze manier kan de zoekmachine de linkjes prima doorlopen, wat bij een dynamisch gegenereerd menu volgens mij nog te betwijfelen is. Dat is ook de reden van deze hele opzet. ServerSide de html en clientside indien nodig eventueel verschillende functionaliteit er aan hangen.

Regel 77 t/m 93 creeër ik een hierarchische object structuur middels geneste menuitemobjecten.

Regel 95 roept de initialiseer functie aan die dynamsich aan de object de Fader functie koppelt. Op regel 13 kan je dus zien dat op de onlcick de functie Fader wordt gekoppeld.

En dan het probleem: de functie Fader wordt aangeroepen: alleen this.opacity is undefined!!! En daar gaat mn hele vraag om: Hoe zorg ik er voor dat dat wel werkt! Het ligt waarschijnlijk aan de verwijzing this. Maar hoe moet dat anders? Als ik in regel 52 in de Fader methode 'this' verander in de globale variabele 'submenuitem' verander dan werkt het wel. Uit Clay z'n tutorial kan ik ook geen oplossing vinden.

Verwijderd

Jij maakt een van de meest gemaakte fouten en volgens mij is er niemand die met JS OO is bezig geweest en nog nooit deze fout heeft gemaakt.

Zodra jij in jouw fader method this.opacity aanroept verwijs jij naar het element document.getElementById immer this is gedefinieerd op dat element, en this op dat element is dus ook dat element. Jij verwijst dus NIET naar het MenuItem object wat je met javascript hebt aangemaakt. Wat je dus moet doen is een scope aanmaken, een scope bevat een referentie naar je object.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
MenuItem.prototype.Fader = function ()
            {
                alert (this.opacity);
            }


wordt dan

MenuItem.prototype.Fader = function ()
            {
                alert (this.obj.opacity);
            }


Waarbij je bij het aanmaken van het object de referentie eraan hangt

PHP:
1
2
3
this.element = document.createElement('DIV');
this.element.obj = this;
document.body.appendChild(this.element);

[ Voor 6% gewijzigd door Verwijderd op 07-03-2005 11:17 ]


Verwijderd

Topicstarter
Okay, das wel duidelijk. Hij probeert dus de opacity eigenschap van het object waarop de onlick plaats vind te pakken, maar die is idd undefined. De koppeling zoals jij hem geeft:

code:
1
2
3
this.element = document.createElement('DIV'); 
this.element.obj = this; 
document.body.appendChild(this.element);


zal voor mij niet opgaan omdat mijn objecten al bestaan. Ik render clientside dus niks. Ik zal in mn Initialize() function in mn for lusje moeten zorgen datie this naar het menuitem object moet wijzen. Zal ik daar eens mee gaan puzzelen!

[edit]

Dit toevoegen deed de truck, was dus best simpel en eigenlijk een somme fout nu ik dit zie!
code:
1
document.getElementById(menuitems.children[i].id).obj = menuitems.children[i];

Bedankt voor alle hulp en uitgebreide informatie!

[ Voor 20% gewijzigd door Verwijderd op 07-03-2005 11:26 ]


  • Clay
  • Registratie: Oktober 1999
  • Laatst online: 25-02 11:17

Clay

cookie erbij?

of je wijst een event handler toe waarin je de scope meesneakt:

code:
1
2
3
4
5
6
this.element = ...apendChild(element);

var self = this;
this.element.onmouseover = function() {
   self.Fader();
}


Binnen Fader heb je dan weer de originele menu item scope, en niet een htmlElement of window. Dat is het zelfde truukje als ik bij timers in de tut doe :) "this" is een superding, maar je moet idd wel ff opletten wat er inzit afhankelijk van waar die staat :P
Memoryleaks zijn wel irritant, en daar is deze constructie wel weer gevoelig voor :{

Instagram | Flickr | "Let my music become battle cries" - Frédéric Chopin


Verwijderd

Maar jouw benadering is wel mooier, want zo zijn je methods niet afhankelijk van scopes. De method doet wat hij moet doen en krijgt de benodigde referenties nog voor de aanroep in zijn schoot geworpen.

Dat het lekt, is jammer, maar ik merk zelf de laatste tijd al niet meer onder dispose methods uit te kunnen komen. Zowat elke cyclic reference, of gebruik van dom lekt in zowel IE als in FF (FF zelfs nog harder dan IE). Dus dan maar een extra dispose op die eventhandler erbij.

Misschien dat Blues zijn ervaringen nog kan delen mbt memory management, gezien het Backbase framework. Ik heb het er met Erik Arvidsson nog over gehad, en hij gaf zelf aan dat ze per direct rekening hebben gehouden met memory management en leaks bij de bouw van Bindows maar dat ook hun het erg veel moeite koste om zaken onder controle te houden.

Er zijn ook geen tools beschikbaar die dit voor je kunnen meten of die kunnen aangeven welke references er nog in memory overblijven (Venkman kon het igg niet meen ik).

[ Voor 37% gewijzigd door Verwijderd op 07-03-2005 11:35 ]


Verwijderd

Verwijderd schreef op maandag 07 maart 2005 @ 11:32:
Misschien dat Blues zijn ervaringen nog kan delen mbt memory management, gezien het Backbase framework.
offtopic:
Ik werk niet aan de Backbase engine, alleen aan implementaties ermee.

Wel durf ik te zeggen dat voor de gemiddelde huis-tuin-en-keuken-website (en zelfs de meeste corporate sites) JS memoryleaks geen echte issues hoeven te zijn. Zodra je gaat praten over complexe webapplicaties, games, ed. begint het echt een struikelblok te worden. Dat ze er bij Bindows rekening mee moeten houden is dan ook geen verassing.

Nou ben ik wel benieuwd wanneer jullie iets als memoryleak beschouwen. In mijn ervaring ligt het grootste probleem bij de reload (met IE). IE lijkt na een reload geen (door JS gebruikt) geheugen vrij te geven, ondanks dat die JS dan natuurlijk geen functie meer heeft.

Verwijderd

Topicstarter
Die van Clay is inderdaad mooier! Die probeerde ik te implementeren volgens onderstaande code:

code:
1
2
3
4
5
6
7
8
9
function Initialize (menuitems)
{
    for (var i = 0; i < menuitems.children.length; i++)
    {
        var self = menuitems.children[i];
        document.getElementById(menuitems.children[i].id).onmouseover = function () { self.Fader() };
        document.getElementById(menuitems.children[i].id).onmouseout = function () { self.Fader() };
    }
}


Dat ging to dusver goed dat waar ik ook met mn muis over ging op het laatste element (d) de functie werd uitgevoerd :) Maar goed, daar kom ik nog wel uit... een ander probleem wat lastiger is is het gebruik van een interval of timeout die een methode moet aanroepen zolang die aan een bepaalde voorwaarde voldoet. Nemen we als voorbeeld de Fade function dan moet de methode net zolang worden aangeroepen als this.opacity == this.opacityend en als hij in-fade this.opacity == this.opacitystart. Ik zie veel voorbeelden dat in mijn situatie vanuit function MenuItem dit geregeld wordt. Werkend met de versie zoals Gordijnstok aanreikte kreeg ik het niet voor elkaar om eenvoudig dit werkend te krijgen. Ik zou het wel voor elkaar krijgen om bij de onmouseover en onmouseout events een functie aan te roepen die FaderControl heet en die die zaken gaat regelen, maar dan ben ik bijna bij de oude versie zoals ik um eerst had. Voor zoiets simpels hoef ik toch niet zo'n workarround te bouwen? Het gebruik van een globale array werd op verschillende plekken afgeraden. Vandaar deze post; hoe kan ik het beste met die timing omgaan?

Verwijderd

[b]Verwijderd schreef op maandag 07 maart 2005 @ 14:07:Nou ben ik wel benieuwd wanneer jullie iets als memoryleak beschouwen. In mijn ervaring ligt het grootste probleem bij de reload (met IE). IE lijkt na een reload geen (door JS gebruikt) geheugen vrij te geven, ondanks dat die JS dan natuurlijk geen functie meer heeft.
Ik beschouw iets als een memoryleak als het object niet meer bestaat, bijvoorbeeld door verwijdering, of door verlaten van de pagina. Maar waarbij wel gealloceerd geheugen actief blijft.

Het geval wil dat ik een tijdje bezig ben met een behoorlijke complexe interface voor het web volgestampt met javascript (de interface draait in principe op javascript), en je bent echt enorm veel tijd kwijt met debugging van code om memory leaks te beperken. Helemaal weg krijg je ze toch niet, maar als je het grootste gedeelte maar pakt.

Het hele probleem rondom memory management was in eerste instantie terug te plaatsen naar de garbage collector in IE, de zgn. mark & sweep garbage collector. Dit is van het type dat geheugen niet vrijgeeft zodra er nog referenties zijn naar het object (de zgn. cyclic references).

Zodra je dus een object met referenties naar een ander object verwijderd, moet je zorgen dat je eerst al deze referenties op null zet, of delete anders blijft geheugen gealloceerd staan. Dit geld dus voor eventhandlers, alle referenties, dom referenties, etc. een grote shitzooi dus :)

Waar we echter laatst achter kwamen is dat FF in bepaalde gevallen 2x zo erg lekt als IE. Iets waarvan ik had verwacht dat ze dit gingen oplossen.

De hit is zelfs nog velen malen groter als je gebruik gaat maken van COM.


btw. Blues, ik had me geregistreerd op de gemailde link voor de backbase developers kit, maar niets meer gehoord, weet jij iets van vertragingen af? Of is dit gewoon een glitch? :)

[ Voor 19% gewijzigd door Verwijderd op 07-03-2005 15:07 ]


Verwijderd

Kun je dit verduidelijken met een paar regels code? :) Want een interval of timeout kun je eigenlijk op dezelfde manier aanpakken.

PHP:
1
2
3
4
5
6
7
8
9
10
11
prototype.foo.fadein(){
  if(this.opacity >= 100){
    return;
  }

  this.opacity++;
  this.element.style.filter = 'alpha(opacity='+this.opacity+')';

  var self = this;
  setTimeout(function(){self.fadein()},1000);
}

Verwijderd

Topicstarter
Wat jij hebt had ik ook. Na wat testen kwam ik erachter dat ik nu tegen het scope probleem aanloop. Ken ik aan 'self' alleen 'this' toe dan wordt de functie Fader niet gevonden, ken ik aan 'self' this.obj toe dan wordt dus wel de functie aangeroepen, maar bestaat this.obj niet meer omdat de referentie this nu naar het object menuitem wijst ipv naar het HTML object wat de eerste keer het geval is wanneer de functie wordt aangeroepen.

Theoretisch zou ik dan de koppeling volgens Clay's methode bouwen en gebruik maken van de this verwijzing ipv this.obj binnen de functie Fader en het zou moeten werken.... Dan ga ik het probleem oplossen die optreed in mn for-lus zoals ik beschreef in mn vorige post.

/me Sooterd is best blij met de JavaScript console van FF :)

Verwijderd

Topicstarter
Nou, het werkt! Ik heb die hele initialisatie functie er even tussen uitgehaald. Bij het aanmaken van het menuitem object initialiseer ik nu gelijk het html object. Net zo makkelijk en het werkt perfect! Ik had alleen verwacht dat elk object z'n eigen timer wel zou gebruiken zodat multi-threading geen probleem zou zijn; maar dat werkt niet en daar was het ook om te doen :'(

Ik heb in ieder geval weer veel geleerd! Ik heb de laatste versie van de code hieronder geplaatst. Misschien zijn er mensen die verbetering hebben en misschien tips om multi-threading goed te laten werken.

Ik bedank voor zover iedereen die met tips en aanvullende info aan kwamen zetten _/-\o_

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<html>

<head>
    <title>Object Oriented JavaScript</title>
</head>

    <script>
        
        var isie = (document.all) ? true : false;
        
        function MenuItem (id, name)
        {
            this.id           = id;
            this.name         = name;
            this.children     = new Array();
            
            this.opacity      = null;
            this.opacitystart = null;
            this.opacityend   = null;
            this.opacitystep  = null;
            this.opacityspeed = null;
            
            this.fadestate    = null;
            this.outfaded     = null;
            
            this.timer        = null;
            
            // initialize html object
            if (document.getElementById(this.id))
            {
                var element = document.getElementById(this.id);
                var self    = this;
                element.onmouseover = function () { self.Fader(false); }
                element.onmouseout = function () { self.Fader(true); }
            }
        }
        
            MenuItem.prototype.SetOpacityValues = function (opacitystart, opacityend, opacitystep, opacityspeed)
            {
                this.opacity      = opacitystart;
                
                this.opacitystart = opacitystart;
                this.opacityend   = opacityend;
                this.opacitystep  = opacitystep;
                this.opacityspeed = opacityspeed;
                
                this.fadestate    = false;
                this.outfaded     = false;          
            }
            
            MenuItem.prototype.AddChild = function (menuitem)
            {
                this.children[this.children.length] = menuitem;
            }
            
            MenuItem.prototype.Fader = function (state)
            {
                var element = document.getElementById(this.id);
                var self    = this;
                
                switch (state)
                {
                    // fade in
                    case true:

                        this.opacity = this.opacity + this.opacitystep
                        
                        if (isie)
                        {
                            element.filters.alpha.opacity = this.opacity;
                        }
                        else
                        {
                            element.style.MozOpacity = this.opacity/100;
                        }
                        
                        if (this.opacity < this.opacitystart)
                        {
                            this.timer = setTimeout(function(){self.Fader(state)}, this.opacityspeed);
                        }
                        else
                        {
                            clearTimeout (this.timer);
                        }
                        
                        break;

                    // fade out
                    case false:
                        
                        this.opacity = this.opacity - this.opacitystep
                        
                        if (isie)
                        {
                            element.filters.alpha.opacity = this.opacity;
                        }
                        else
                        {
                            element.style.MozOpacity = this.opacity/100;
                        }
                        
                        if (this.opacity > this.opacityend)
                        {
                            this.timer = setTimeout(function(){self.Fader(state)}, this.opacityspeed);
                        }
                        else
                        {
                            clearTimeout (this.timer);
                        }

                        break;
                }
            }

    </script>

<body>

    <ul>
        <li><a id="a" href="#" style="filter: alpha(opacity=100); -moz-opacity: 1.0">a</a></li>
        <li><a id="b" href="#" style="filter: alpha(opacity=100); -moz-opacity: 1.0">b</a></li>
        <li><a id="c" href="#" style="filter: alpha(opacity=100); -moz-opacity: 1.0">c</a></li>
        <li><a id="d" href="#" style="filter: alpha(opacity=100); -moz-opacity: 1.0">d</a></li>
    </ul>

    <script type="text/javascript">
            
        var opacitystart = 100;
        var opacityend   =  40;
        var opacitystep  =   4;
        var opacityspeed =  40;
        
        var menu;
        var menuitem;
        var submenuitem;
        
        menuitem = new MenuItem ('root', 'root');
            
            submenuitem = new MenuItem ('a', 'item a');
            submenuitem.SetOpacityValues (opacitystart, opacityend, opacitystep, opacityspeed);
            menuitem.AddChild (submenuitem);
            
            submenuitem = new MenuItem ('b', 'item b');
            submenuitem.SetOpacityValues (opacitystart, opacityend, opacitystep, opacityspeed);
            menuitem.AddChild (submenuitem);
            
            submenuitem = new MenuItem ('c', 'item c');
            submenuitem.SetOpacityValues (opacitystart, opacityend, opacitystep, opacityspeed);
            menuitem.AddChild (submenuitem);
            
            submenuitem = new MenuItem ('d', 'item d');
            submenuitem.SetOpacityValues (opacitystart, opacityend, opacitystep, opacityspeed);
            menuitem.AddChild (submenuitem);
            
    </script>

</body>

</html>


[edit 1]

Ik heb de clearTimeout (this.timer); op beide plekken in de functie Fader verwijderd en eenmaal helemaal aan het begin van de functie geplaatst. Nu werkt het dus goed!

Klein offopic vraagje: waarom flikkert het element in FF als deze weer een opacity 100% krijgt bij een fade-in?

[edit 2]
Flikkering komt door een bug als ik um tot 0.99 laat lopen gaat het prima!

Iedereen nogmaals bedankt!!

[ Voor 18% gewijzigd door Verwijderd op 07-03-2005 16:21 ]


Verwijderd

Ah nice.. :)
Pagina: 1