Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [jQuery] Mój zbugowany preloader obrazków
Forum PHP.pl > Forum > Po stronie przeglądarki > JavaScript
starach
Hej,

Dawno dawno tematu... czytałem książkę o JS w której zawarty był rozdział o preloadingu obrazków. Chciałem z pamięci wykonać port tego skryptu na jQuery, ale zdaje się że coś spietruszyłem.

Jak najadę na przycisk od prawej bądź lewej strony to obrazek się podmienia, a potem znika. Zależy to też od szybkości z jaką najadę na owy link i z niego wyjdę.

  1. #header ul { position:relative; top:62px; left:250px; width:489px; height:38px; margin:0; padding:0;
  2. list-style:none; background:url('/images/Menu.png') no-repeat; }
  3. #header ul li { float:left; margin:9px 0 5px 30px; border:1px solid #F00; }
  4. #header ul li.first { margin-left:20px; }

  1. <ul>
  2. <li><a href="#" title="Link 1"><img src="/images/Menu/link_1.png" alt="Link 1" /></a></li>
  3. <li><a href="#" title="Link 2"><img src="/images/Menu/link_2.png" alt="Link 2" /></a></li>
  4. <li><a href="#" title="Link 3"><img src="/images/Menu/link_3.png" alt="Link 3" /></a></li>
  5. <li><a href="#" title="Link 4"><img src="/images/Menu/link_4.png" alt="Link 4" /></a></li>
  6. <li><a href="#" title="Link 5"><img src="/images/Menu/link_5.png" alt="Link 5" /></a></li>
  7. </ul>

[JAVASCRIPT] pobierz, plaintext
  1. $m = new Menu();
  2. $m.init();
  3.  
  4. function Menu()
  5. {
  6. this.aImg = new Array();
  7. this.aImgHover = new Array();
  8. var $ths = this;
  9.  
  10. this.init = function()
  11. {
  12. $("#header li a").each(
  13. function()
  14. {
  15. $ths.evt_HoverAppend($(this));
  16. });
  17. }
  18.  
  19. this.evt_HoverAppend = function($link)
  20. {
  21. $iImgIndex = this.aImg.length;
  22. $Img = $("img", $link);
  23. $Img.attr("index", $iImgIndex);
  24.  
  25. // Define hover image by adding -hover suffix before its extension
  26. $SImgSrc = new String($("img", $link).attr("src"));
  27. $sImgSrcExt = $SImgSrc.substring($SImgSrc.length - 3, $SImgSrc.length);
  28. $sImgHoverSrc = $SImgSrc.substring(0, $SImgSrc.length - 4) + "-hover." + $sImgSrcExt;
  29.  
  30. $ImgHover = new Image();
  31. $ImgHover.src = $sImgHoverSrc;
  32.  
  33. this.aImg.push($Img);
  34. this.aImgHover.push($($ImgHover).attr("index", $iImgIndex));
  35.  
  36. $link.hover(
  37. function()
  38. {
  39. $Img = $("img", this);
  40. $Img.replaceWith($ths.aImgHover[$Img.attr("index")]);
  41. },
  42. function()
  43. {
  44. $Img = $("img", this);
  45. $Img.replaceWith($ths.aImg[$Img.attr("index")]);
  46. });
  47. }
  48. }
[JAVASCRIPT] pobierz, plaintext
erix
Możesz wyjaśnić, dlaczego w JS chcesz robić coś, co możesz robić w CSS?
starach
Jak sama nazwa wskazuje jest to preloader. Jeśli obrazek jest za duży, a użytkownik ma badziewny net to chwilę potrwa zanim mu się dany element strony załaduje. Może to spowodować przy np. menu brak elementu po najechaniu na niego.

Nie mniej jednak będę musiał prawdopodobnie zrezygnować z tej metody skoro nikt nie wiem gdzie może leżeć błąd.
zegarek84
jako, że jQuery nie używam oraz nie dałeś przykładu live to nie musisz czytać bo to może się okazać "bzdurą"

pierwsze napiszę gdzie mi się wydaje, że to się może sypać - zważywszy na to, iż napisałeś o szybkości najazdu myszką na element... i dalej korzystasz z metody .replaceWith do podmiany obiektu w drzewie DOM - gdzie to też z tego obiektu który podmieniasz przechowujesz informację także... w ogóle to takie pytanie po co podmieniasz ten element?? - czemu nie skorzystasz ze standardowej podmiany źródła z obiektu image (przykład)questionmark.gif (i to też raczej będzie jednym z rozwiązań)... lub informację przechowuj w samym linku (choć to nie do końca - może opiszę co się wg. mnie tam dzieje)...

w css nie ostylowałeś wielkości/rozmiaru linków, więc podczas podmieniania elementu w pierw następuje usunięcie starego (link się "kurczy" gdyż chwilę nie ma treści) po czym wstawiasz obrazek, jednak zanim wstawisz obrazek myszką możesz znaleść się poza pustym linkiem (.mouseleave) i od razu wykonujesz drugą metodę z hover'a (i tu raz zdążysz podmienić obrazek na nowy i będzie informacja co i jak i wróci na stary, a i może się zdarzyć, że z nowym nie zdążysz i błąd będzie na leave bądź enter jeśli ten link będzie "skakał")... idąc dalej analogiczną sytuację możesz mieć przy bardzo szybkim przesunięciu myszki nad linkiem - spróbujesz wykonać drugą akcję podczas gdy jeszcze tam nie zostanie wczytany element obrazka...

w skrócie - podmieniaj .src obrazka lub określ rozmiar linku i informacje dodatkowe przechowuj w tym linku a nie w obrazku (i nie bierz za pewnik, że tam będzie element obrazka, że zdążysz go wstawić)...
starach
Ehh oferma ze mnie. Zorientowałem się o co ci chodzi po pierwszym akapicie. I oczywiście zaczęło działać.

Mam jeszcze jedno pytanie dotyczące stricte jQuery. Jak w obiekcie wyselekcjonowanym za pomocą jQuery przechować informację?
np. Jeśli bym chciał opatulić link w jQuery $($link) to jak mam do niego przypisać zmienne overImage i outImage, żebym mógł się do nich odwołać w handlerze zdarzeń onmouseover i onmouseout?

[JAVASCRIPT] pobierz, plaintext
  1. function Menu()
  2. {
  3. this.init = function()
  4. {
  5. for(i=0; i<document.images.length; i++)
  6. {
  7. $image = document.images[i];
  8. if($image.parentNode.tagName == "A" && $image.parentNode.parentNode.parentNode.id == "menu")
  9. {
  10. this.evt_HoverAppend($image);
  11. }
  12. }
  13. }
  14.  
  15. this.evt_HoverAppend = function($image)
  16. {
  17. $link = $image.parentNode;
  18.  
  19. // Define hover image by adding -hover suffix before its extension
  20. $SImgSrc = new String($image.src);
  21. $sImgSrcExt = $SImgSrc.substring($SImgSrc.length - 3, $SImgSrc.length);
  22. $sImgHoverSrc = $SImgSrc.substring(0, $SImgSrc.length - 4) + "-hover." + $sImgSrcExt;
  23.  
  24. $link.overImage = new Image();
  25. $link.overImage.src = $sImgHoverSrc;
  26. $link.outImage = new Image();
  27. $link.outImage.src = $image.src;
  28.  
  29. $link.onmouseout = function()
  30. {
  31. this.childNodes[0].src = this.outImage.src;
  32. }
  33. $link.onmouseover = function() {
  34. this.childNodes[0].src = this.overImage.src;
  35. }
  36. }
  37. }
[JAVASCRIPT] pobierz, plaintext
erix
[JAVASCRIPT] pobierz, plaintext
  1. $().data()
[JAVASCRIPT] pobierz, plaintext
zegarek84
Cytat(starach @ 6.04.2010, 18:51:05 ) *
Ehh oferma ze mnie. Zorientowałem się o co ci chodzi po pierwszym akapicie. I oczywiście zaczęło działać.

Mam jeszcze jedno pytanie dotyczące stricte jQuery. Jak w obiekcie wyselekcjonowanym za pomocą jQuery przechować informację?
np. Jeśli bym chciał opatulić link w jQuery $($link) to jak mam do niego przypisać zmienne overImage i outImage, żebym mógł się do nich odwołać w handlerze zdarzeń onmouseover i onmouseout?

heh winksmiley.jpg - odpowiedź stricte jQuery padła powyżej ale... to jest JS i chyba warto dalej przeczytać winksmiley.jpg

js jest mimowolnie silnie obiektowy - nawet zwykła funkcja potrafi być obiektem - nie sorki - zapędzam się ;p..

gdy przypisujesz anonimową funkcję do danego zdarzenia to suma sumarum ta funkcja jest zawsze inna - jak to można wykorzystaćquestionmark.gif

przypisując te zdarzenia w pętli tylko raz musisz pamiętać indeks zapisanej zmiennej (źródła/ścieżki w zmiennej) z over bądź out i przypisując zdarzenie robisz np. tak:
[JAVASCRIPT] pobierz, plaintext
  1. $link.onmouseout = function()
  2. {
  3. this.childNodes[0].src = outImageSrc[2];/* jest to np. drugi obrazek i outImageSrc jest np. tablicą - funkcja zapamięta referencję do tej zmiennej ;) - więc potem nie musisz pamiętać */
  4. }
[JAVASCRIPT] pobierz, plaintext

albo jeszcze inaczej (skoro i tak za każdym razem przypisujesz nową funkcje ;p) możesz trzymać referencję do obrazków w jakiejś tablicy i:
[JAVASCRIPT] pobierz, plaintext
  1. $link.onmouseout = function()
  2. {
  3. obrazek[2].src = outImageSrc[2];
  4. }
[JAVASCRIPT] pobierz, plaintext

idąc dalej mały przykład gdzie nie musisz pamiętać w ogóle referencji do zmiennych - trochę przykład niby pod wyciek pamięci ale skoro to raz wykonasz w konstruktorze tego handlera to to Ci nie grozi (a żeby był gdzieś uchwyt do tych obiektów to też w tablicy możesz pamietać - tylko daję przykład że wszystkim zmiennym możesz przypisać null) - takie coś se na szybko po treningu napisałem i hula winksmiley.jpg [jak pisałem na szybko to darowałem se preload - choć to jedna linijka ;p]:
[JAVASCRIPT] pobierz, plaintext
  1. function imageSrc($over, $out){
  2. this.over=function(){this.src=$over;};
  3. this.out=function(){this.src=$out;};
  4. }
  5.  
  6. function obrazki(){
  7. var ob, over, src;
  8.  
  9. ob=document.getElementById('ob1');
  10. over='http://www.internetmaker.pl/img/7_porad_dla_mistrzow_css,2,38,120,80,b10a5c5c.jpg';
  11. src = new imageSrc(ob.src, over);
  12. ob.onmouseout=src.over;
  13. ob.onmouseover=src.out;
  14.  
  15.  
  16. ob=document.getElementById('ob2');
  17. over='http://www.internetmaker.pl/images/ikony/nc02.gif';
  18. src = new imageSrc(ob.src, over);
  19. ob.onmouseout=src.over;
  20. ob.onmouseover=src.out;
  21.  
  22. ob=null;src=null;over=null;
  23. }
[JAVASCRIPT] pobierz, plaintext


PS. skoro korzystasz z jQuery to używaj mouseenter a nie over gdyż over tutaj może Ci się wykonać 2 razy choć tego nie zauważysz - czyli enter na to jest optymalniejszy - podobnie z leave i out... idąc dalej to użyj tego hover gdyż to połączenie mouseenter i leave winksmiley.jpg
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.