Autor Zpráva
XeeD
Profil
Problém:
- pořád se mi nedaří pochopit objektový model Javascriptu. Štve mě to :-) Takže tu zkusíme vyřešit jeden konkrétní problém, a zkusíme na něm pochopit útroby JS

- Úkol - Chci udělat objekt, který by se dal použít k animování určitých prvků stránek. Dejme tomu třeba dynamickou změnu průhlednosti. Předá se mu prvke, který chceme zprůhlednit/zneprůhlednit a dobu, za jakou se to vykoná. Chci aby po dokončení této změny zavolal nějakou funkci, pokud se mu na začátku předá (+ nějaké parametry). Chci, aby bylo možné animovat několik prvků na stránce naráz a asynchronně. A aby bylo možné v průběhu animace dělat i jiné věci (XMLHttpRequest, atd.). Pokud by bylo třeba objekt začít animovat "jiným směrem" (zprůhleňuje se a je potřeba ho začít znovu zneprůhledňovat), tak by se měla stávající animace zastavit.
- představuji si to nějak takhle:


new Anim.Fade(2, $('loading'), {onComplete:this.onFadeStop, params:{foo:bar, dummy:'foo'}});


Definujeme si funkce pro usnadnění:

function $(id) { return document.getElementById(id) }
function _(el) { return document.createElement(el) }
XeeD
Profil
Takže, takový první nástřel (ještě jsem zapomněl - chtělo by to Firebug)


HTML (jen kostra)

<html>
<head>
<script src='anim.js' type='text/javascript'></script>
</head>
<body>

<span id='loading1'>Nahrávám</span>
<div id='loading2'>Nahrávám...</span>

<ul id='list'>
<li>První</li>
<li>Druhý</li>
<li>Třetí</li>
</ul>

</body>
</html>


anim.js

var Anim = {}

// Konstruktor
Anim.Fade = function Fade(target, duration) {
this.step = 50 / (duration * 1000);
this.target = target;
this.interval = window.setInterval(this.onInterval, 50);
// Debug
console.log(this);
// onComplete
if (arguments[2]) {
this.onComplete = arguments[2];
}
}

// Přidáme metody
Anim.Fade.prototype = {
onComplete: null,
onInterval: function() {
this.target.style.opacity -= this.step;
opac = this.target.style.opacity;
// Debug
console.log(opac);
if (opac >= 1 || opac <= 0) {
window.clearInterval(this.interval);
if (this.onComplete) {
this.onComplete.action(this.onComplete.params);
}
}
}
}

// Test
new Anim.Fade($('loading1'), 2);


Což by podle mě mělo fungovat (v IE ne, to nepodporuje opacity, to dodělám nakonec).

Výsledek? Každých 50 ms se vyvolá chyba na řádku 22 (this.target has no properties).
XeeD
Profil
Je to na adrese http://stack.31gangsters.com/js/1/
los
Profil *
Pár drobných pripomienok:
1. "Anim.Fade = function Fade(target, duration)" - týmto si chcel asi vytvoriť funkciu (konštruktor), ktorú budeš mať prístupnú *iba* cez Anim.Fade, takže by stačilo použiť anonymnú funkciu "Anim.Fade = function(target, duration)".

2. "this.interval = window.setInterval(this.onInterval, 50);" - keď nastaviš interval, tak spúšťaná funkcia (this.onInterval) je spustená z iného kontextu, takže v this už nenájdeš objekt typu Fade. V JavaScripte je this kľúčové slovo a nie premenná. Z toho vyplýva aj tá chyba "this.target has no properties". Môžeš to volať napr. nejako takto: "var t = this; this.setInterval(function() { t.onInterval() }, 50);".

3. "if (arguments[2]) {this.onComplete = arguments[2];}" - bolo by oveľa prehľadnejšie, keby bol ten argument pomenovaný priamo v deklarácii funkcie.
los
Profil *
Oprava bodu 2 - bolo tam navyše jedno this: Môžeš to volať napr. nejako takto: "var t = this; setInterval(function() { t.onInterval() }, 50);".
ah01
Profil
To $('loading1') nemůžeš použít dřív, než ten element existuje. Takže

onload = function(){
new Anim.Fade($('loading1'), 2);
}


Pokud chceš pochopit JS tak ti doporučuji přednášky Douglas Crockforda - http://developer.yahoo.com/yui/theater/ (jsou to 3 přednášky, a na té stránce jsou poslední 2 přehozené).
peta
Profil
XeeD
1. validita
<DIV id='loading2'>Nahrávám...</SPAN>
jinymi slovy, div2 neni ukoncen

2. chyba JS konzoly
this.target.style.opacity -= this.step;
- jednak opacita nemusi byt definovana (pokud nemas IE) a od null neco odecitat...
- this.target has no properties
znamena, ze proste tam zadne style neexistuje
alert(this)
alert(this.target)
x=this;
var i,t; t=""; for (i in x) t+=i+":"+x[i]+", "; alert(t);
x=this.target;
var i,t; t=""; for (i in x) t+=i+":"+x[i]+", "; alert(t);

jako, nechce se mi zkoumat script, ale rekl bych, ze pracujes s neexistujicim objektem.

Anim.Fade.prototype= {
onInterval: function() {

this.target.style.opacity -= this.step;
Anim.Fade.onInterval.target = null ? si myslim ja
peta
Profil
tak viz ah01
Ty to poustis v HEAD, ale ten DIv jeste neexist
XeeD
Profil
Díky, myslím že jsem to pochopil, chyba byla v tom kontextu - opravená verze je na http://stack.31gangsters.com/js/2/
skript na http://stack.31gangsters.com/js/2/anim.js

- pokud je animace jen jedna tak to funguje bezvadně.
- pokud je animací víc, tak funguje jen jedna. Nechápu proč?

http://stack.31gangsters.com/js/3/ - více animací
http://stack.31gangsters.com/js/3/anim.js - skript
XeeD
Profil
Myslel jsem, že když vytvořím dvě instance (new Anim.Fade - je to vůbec vytváření instancí?), tak bude mít každá jiné properties?
los
Profil *
Je to vytváranie inštancií.

V konštruktore pracuješ s globálnymi premennými _this a onInterval. Zadeklaruj ich pomocou var.
XeeD
Profil
Ha! :-) Už to funguje, nevěděl jsem že vlastně pokaždé přepisuji _this. Díky moc za vaši pomoc, myslím že jsem zas o kousek dál (přednášky se stahují). Opravil jsem tam ještě nějaké chyby se zaokrouhlením, můžete si to prohlédnout na http://stack.31gangsters.com/js/4/
Toto téma je uzamčeno. Odpověď nelze zaslat.