[JS] Utworzenie zdarzenia onLoad dla FF i Opery

0

Witam,
Mam takie pytanie, na stronce w podkładzie mam dużą fotkę, ładuję się ona powiedzmy z 5 sekund. Cała zawartość strony jest w ukrytym divie , widoczny jest tylko div z napisem trwa ladowanie strony.
W zdarzeniu onLoad wywołuję funkcję która ukrywa diva z progresem i ustawia wlasciwosc drugiego diva z treścią na widzialną. Wszystko fajnie działa ale tylko w IE.

Dla FF i Opery użyłem:
document.addEventListener("DOMContentLoaded", function(){moja_funkcja();}, false);

Ale problem znowu jest taki ze DOMContentLoaded nie zwraca uwagi na ładowanie grafiki i wykonuje się szybciej niz onLoad. Więc rozwiązanie upada.
Jak zrobić coś takiego dla FF i Opery a dokładniej czy istnieje jakieś zdarzenie które jest wywoływane po załadowaniu grafik na stronie ?

0

Zdarzenie "load" (onload) działa we wszystkich przeglądarkach i to właśnie go powinieneś użyć w tym wypadku.

DOMContentLoaded czeka na załadowanie całego drzewa DOM dokumentu, czyli generalnie jego zawartości tekstowej. Nie czeka na załadowanie obrazków, ramek, czy czego tam jeszcze (teoretycznie nie musi nawet czekać na ładowanie skryptów i stylów, w praktyce jest trochę inaczej).

Load (onload) z kolei czeka na załadowanie całej strony wraz z obrazkami. O to właśnie Ci chodzi.

Podejrzewam, że problemem jest to, że piszesz "onload" zamiast "load". Pisze się i tak i tak, ale w różnych miejscach. Funkcje zaczynające się od "on" to stary model obsługi zdarzeń. W tej nomenklaturze napisałbyś:

window.onload = moja_funkcja_obslugi;

Nie polecam jednak tego sposobu, choć działa on wszędzie. Problem powstanie, gdy zechcesz dodać drugą funkcję do onload. W ten sposób będzie to bardzo utrudnione.

Dlatego użyj innego modelu, opracowanego przez W3C, z funkcjami addEventListener, o tak:

window.addEventListener('load', moja_funkcja_obslugi, false);

Zauważ jednak, że tutaj ^^ już się nie pisze "onload", tylko po prostu "load" (tak samo nie onclick, tylko click i tak dalej). Stare IE nie obsługują funkcji addEventListener, ale na szczęście Microsoft wymyślił i zaimplementował swój odpowiednik: funkcję attachEvent (już z "on" -- tak sobie wymyślili w MS):

window.attachEvent('onload', moja_funkcja_obslugi, false);

0

Witam serdecznie. Ja mam problem z funkcją load. Stosowałem różne wersje :

window.onload = function() { ...
$(window).load(function() { ...

Pod ie7,ie8,ff wszystko działa bez problemu. Skrypt uruchamia się gdy grafiki zostaną wczytane. Pod operą skrypt startuje zanim grafiki zostaną wczytane...

0

To jest nieprawda :). Przynajmniej nie powinno być to prawdą. window.onload w Operze działa jak należy (zgodnie ze specyfikacją) -- odpala po załadowaniu obrazków. Zrobiłem sobie stronę testową i sprawdziłem to teraz. Test potwierdził teorię.

Daj link do strony, gdzie występuje ten błąd. Albo daj kod.

0

(function($){
$.fn.galeric = function(options) {
var defaults = { jakieś tam zmienne };
var options = $.extend(defaults, options);
return this.each(function() {
$(window).load(function() {

                                                                         jakies tam funkcje };

			});
		});
};

})(jQuery);

"Jakieś tam funkcje" mają się odpalić gdy opera wczyta kilka obrazków. W ie i ff wszystko gra..

0

Dziwne. A sprawdź najprostszy przypadek:

window.onload = function() { alert('window.onload'); }
window.addEventListener('load', function() { alert('window.addEventListener(load)'); }, false);
$(window).load(function() { alert('$(window).load'); });

Wszystkie 3 sposoby u mnie działają poprawnie w najnowszej Operze.

Btw. czy obrazki, na których wczytanie chcesz czekać, są dołączane do dokumentu dynamicznie (przez skrypty)? :P

0

U mnie w operze, funkcje zawarte w funkcji load także działają, ale odpalają się zanim do pamięci przeglądarki wczytane są grafiki przez co widać ich stopniowe wczytywanie. Może wpływ ma to, iż obrazki mają narzucony przez css atrybut display:none.. Nie znam dokłądnej specyfikacji opera, ale może ona wtedy nie wczytuje ich...

0

Tak jak myślałem. Img które mają narzucone display:none w ff i ie i tak są wczytywane wiec funkcja load czeka na ich załadowanie. Opera nie ładuje img które mają display:none...

0

Tak, wygląda na to, że masz rację. Gdy obrazki mają display: none, to ich wczytywanie (o ile są w ogóle wczytywane!) nie wpływa na zdarzenie load. Zauważyłem jednak, że gdy tagów img z ukrytymi obrazkami dodasz atrybut onload="" (tak, może być nawet pusty!), to wszystko działa jak należy.

0

Dokładnie!. Img z atrybutem onload="" są wczytywane przed funkcją load w operze... Dziwne. Myślałem aby display:none zmienić visiblity:hidden ale wtedy musiałbym przebudowywać cały skrypt galerii... Musze poszukać coś o tym problemie bo jakoś boli mnie dodawanie onload="" do każdego img..

0

Widzę że tak opera działa i nic tego nie zmieni. Elementy z atrybutem diaply:none nie są wczytywane do pamięci. Można się bawić np.

{
display:block;
position: absolute;
left: -9999px;
}

Zostanie więc dodawanie do każdego obrazka atrybutu onload=""

Pozdrawiam

0

Wygląda na to, że do pisania pluginów jQuery podchodzisz co najmniej w miarę porządnie (korzystasz z zaleceń odnośnie stosowania funkcji $, domyślnych opcji itd.). Wydaje mi się, że mogę Ci dać jeszcze jedną radę -- bardziej na przyszłość, bo teraz pewnie już nie masz opcji żeby to przerobić.

To się sprawdza głównie wtedy, gdy nie masz animacji. Kontroluj wygląd elementów nie w JavaScripcie, tylko w CSS. Czyli nie pisz element.style.display = 'none' i potem nie sprawdzaj, czy element.style.display === 'none'. Zamiast tego po prostu nadaj elementowi klasę. Np. 'hidden'. $(element).addClass('hidden'), a sprawdzaj, czy element.hasClass('hidden'). Wtedy definiujesz sobie w CSS regułę:

.hidden {
  ...
}

I nie ma w zasadzie znaczenia, co jest wewnątrz niej. Czy display: none, czy pozycjonowanie. To czysta prezentacja i JavaScript na tym nie polega.

Trochę trudniej to zrobić, gdy korzystasz z prostych, automatycznych animacji jQuery. Np. funkcja hide używa display: none z tego co pamiętam i nie bardzo możesz to ominąć. Jedynie po zakończeniu animacji mógłbyś usunąć display: none i (nawet zanim usuniesz display) dodać odpowiednią klasę.

0

Dokładnie. Funkcja fadeIn, czy fadeOut na koncu wywołuje display:none.. Dlatego visibility u mnie odpada..

0

Dzięki za odpowiedzi. Stosuję stylizację przez klasy css, ale akurat tu chciałem wykorzystać fadeIn i fadeOut. Ogólnie zajmuje się css + (x)xtml - www.getica.pl ale od jakiegoś tygodnia zaciekawiło mnie jQuery. Rozwiązałem ten problem w pewien sposób :

W css ustawiłem dla img - visibility:hidden;
Następnie na początku pluginu dla tych img : $(options.full_div+' img').hide();
I w funkcji load : $(options.full_div+' img').css("visibility", "visible");

Rozwiązało to problem z operą.

Pozdrawiam

0

W poprzednim poście nie wymyśliłem, a może nie zdajesz sobie z tego sprawy...

fadeIn i fadeOut mają też drugi, opcjonalny parametr o nazwie callback. Jest to funkcja, która zostanie wywołana po zakończeniu animacji.

Dzięki temu możesz łatwo napisać własne funkcje osłonowe w rodzaju (uwaga: piszę na sucho :) ):

jQuery.fn.myFadeOut = function(speed, callback) {
  this.fadeOut(speed, function() {
    this.style.display = ''; // skasuje display: none
    this.style.visibility = 'hidden'; // albo addClass
    if (jQuery.isFunction(callback)) {
      callback.call(this);
    }
  });
};

Musiałbyś stworzyć też analogiczną funkcję myFadeIn, która usuwałaby visibility='hidden'.

Ba, możesz nawet podstawić taką funkcję zamiast oryginalnej fadeOut (wcześniej sejwowałbyś sobie oryginalną funkcję fadeOut do jakiejś zmiennej), tylko to by było odrobinę niebezpieczne!

edit: Najważniejsze, że sobie poradziłeś. Świetnie.

0

Nie za bardzo rozumiem to. Ja dopiero raczkuje w js i jquery .. :

if (jQuery.isFunction(callback)) {
  callback.call(this);
}
0

To prawie to samo co:

if (typeof callback === 'function') {
  callback();
}

Zrobiłem to po to, żeby nasza funkcja osłonowa myFadeOut też mogła przyjmować ten opcjonalny parametr callback. Pierwsza z tych trzech powyższych linijek sprawdza, czy go podano i czy jest to funkcja (gdyby parametru nie podano, to typeof callback zwróciłoby 'undefined'). Tylko że to typeof nie zawsze działa (długa historia), więc użyłem funkcji jQuery.isFunction(v). Ona po prostu sprawdza, czy v jest funkcją. Jeśli jest, to zwraca true -- w przeciwnym wypadku zwraca false. Efekt ten sam, tylko kod bardziej "przenośny".

Druga linijka, callback(), to po prostu wywołanie funkcji przekazanej w parametrze callback.

Czyli całość działa tak, że jeśli naszej funkcji myFadeIn podano w drugim parametrze funkcję do odpalenia po zakończeniu animacji, to w tym momencie ją odpalamy.

A czemu napisałem callback.call(this) zamiast po prostu callback()? Cóż, funkcja składowa call to element języka JavaScript. Funkcja ta jest dostępna w każdej zmiennej, która... jest funkcją.

Działa to tak, że gdy napiszesz:

fff.call(kontekst)

...to wewnątrz funkcji fff this będzie wskazywało na obiekt kontekst. A zgodnie ze specyfikacją jQuery, w funkcji callback this powinno wskazywać na bieżący element (element drzewa DOM). To trochę śmieszna sprawa, bo w grę wchodzi tu błąd języka JavaScript... Gubiony jest kontekst, czyli właśnie wartość this. W naszej funkcji anonimowej, w której mamy linijki "this.style.display = ...." this jest ustawiony na bieżący element DOM. Zapewnia nam to jQuery. Na końcu funkcji chcemy wywołać funkcję callback. Ale jakbyśmy wywołali ją tak:

this.style.display = ''; // tu this wskazuje na element DOM!
callback();

To wewnątrz funkcji callback this nie wskazywałoby już na element DOM, tylko... obiekt globalny window. To jest właśnie ten błąd języka JavaScript. Jeden z bardziej irytujących. Kontekst nie jest zachowany. A my chcemy, by wewnątrz callback this wskazywało na to samo, na co wskazuje this w funkcji zewnętrznej (tej z this.style.display itd.). Więc robimy:

callback.call(this);

To wywołuje funkcję callback tak samo jakbyś napisał po prostu callback(); z tą jednak różnicą, że w funkcji callback this będzie ustawione na to, na co jest ustawione this w funkcji zewnętrznej.

To jest zawiłe do tłumaczenia i trudne do zrozumienia (bo jest głupie!), ale gdy to zjarzysz to wydaje Ci się to już bardzo proste.

edit: To może powiem po co jeszcze w ogóle to robimy :D

Funkcja fadeOut ma drugi parametr, który zwą sobie callback i który jest funkcją wywoływaną po zakończeniu animacji. Parametr ten jest opcjonalny. My chcemy, by nasza własna funkcja myFadeOut też miała taki opcjonalny parametr. Na wypadek, gdyby ktoś chciał go użyć. Więc go papugujemy. Dzięki temu można będzie wywołać:

$(...).myFadeOut('slow', function() {
  alert('animacja zakończona!');
});

Ale Ty pewnie na razie nie będziesz z tego korzystał, tylko napiszesz tak (możesz, bo parametr jest opcjonalny -- sprawdzamy za pomocą isFunction, czy podano funkcję i próbujemy ją wywołać tylko gdy ją podano!):

$(...).myFadeOut('slow');
0

To że fukcja fadeIn czy FadeOut jak 99% funkcji jQuery może być wywoływana z dodatkowym parametrem-funkcją która odpali się po zakończeniu animacji - wiedziałem :) Dziękuje za ciekawe i dające do myślenia wyjaśnienie tego kodu. Oby więcej ludzi, którzy "tak" służą pomocą. Wielkie dzięki. Jak pisałem dopiero raczkuje w tej tematyce, ale z dnia na dzień robi się ciekawiej. Do tej pory szlifowałem css i W3C. Na zakończenie wklejam linka do moich wypocin :

www.getica.home.pl/green/galeric1.0/galeria.html
www.getica.home.pl/green/galeric2-1.0/galeria.html

Pozdrawiam

1 użytkowników online, w tym zalogowanych: 0, gości: 1