Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Rotator zdjęć - pierwsze starcie
Forum PHP.pl > Forum > Po stronie przeglądarki > JavaScript
wiktorc
Witam!
Ostatnio chciałem pogłębić moją znikomą wiedzęsmile.gif na temat javascript'u/jquery. Napisałem wczoraj prosty rotator zdjęć. Prosiłbym o jakąś opinie lub uwagi osób które mają ogarnięcie w js. Może informacje co mógłbym poprawić na co zwracać uwagę. Krytyka mile widziana smile.gif

plik z kodem: image_rotator

html:
  1. <div class="wrapper">
  2. <div class="buttons">
  3. <a href="#" class="left"><</a>
  4. <a href="#" class="right">></a>
  5. </div>
  6. <div class="image-wrapper">
  7. <img src="img/1.jpg" class="active" alt="1">
  8. <img src="img/2.jpg" alt="2">
  9. <img src="img/3.jpg" alt="3">
  10. </div>
  11. <div class="pagination"></div>
  12. </div>


css:
  1. .wrapper {
  2. margin: 0 auto;
  3. position: relative;
  4. width: 600px;
  5. height: 350px;
  6. overflow: hidden;
  7. border: 4px solid grey;
  8. }
  9. .wrapper .image-wrapper img{
  10. position: absolute;
  11. display: none;
  12. height: 378px;
  13. margin: 0 auto;
  14. background: white;
  15. }
  16. .wrapper .image-wrapper img.active {
  17. z-index:1;
  18. display: inline-block;
  19. }
  20. .wrapper .buttons {
  21. font-family: arial;
  22. font-weight: bold;
  23. color: white;
  24. margin: 0 auto;
  25. width: 100%;
  26. position: absolute;
  27. z-index: 99;
  28. top: 150px;
  29.  
  30. }
  31. .wrapper .buttons a {
  32. text-decoration: none;
  33. color: #fff;
  34. }
  35. .wrapper .buttons .left{
  36. position: absolute;
  37. left: 10px;
  38. display: block;
  39. background: rgba( 0,0,0,0.5);
  40. padding: 5px 10px;
  41.  
  42. }
  43. .wrapper .buttons .right{
  44. position: absolute;
  45. right: 10px;
  46. display: block;
  47. background: rgba( 0,0,0,0.5);
  48. padding: 5px 10px;
  49. }
  50.  
  51. .wrapper .pagination {
  52. background: rgba( 0,0,0,0.5);
  53. position: absolute;
  54. padding: 5px;
  55. bottom: 5px;
  56. left: 10px;
  57. z-index: 3;
  58. }
  59. .wrapper .pagination .page_el {
  60. float: left;
  61. height: 10px;
  62. width: 10px;
  63. margin: 1px;
  64. border: 1px solid #fff;
  65. }
  66. .wrapper .pagination .checked {
  67. background: #ddd;
  68. }


js:
  1. var nextImg = function() {
  2. var imgs = $('.image-wrapper img');
  3. var active_obj = $('.active');
  4. var next_img = active_obj.next();
  5. var first_img = imgs.first();
  6.  
  7.  
  8. if( !imgs.last().hasClass('active')){
  9. next_img.css("z-index", "2")
  10. next_img.fadeIn( 800, function() {
  11. active_obj.css("z-index","1");
  12. active_obj.css("display","none");
  13. active_obj.removeClass('active');
  14. next_img.addClass('active');
  15. });
  16. }else{
  17. first_img.css("z-index", "2");
  18. active_obj.css("z-index", "1");
  19. first_img.fadeIn( 800, function() {
  20. active_obj.css("z-index","1");
  21. active_obj.css("display","none");
  22. active_obj.removeClass('active');
  23. first_img.addClass('active');
  24. });
  25. };
  26. return 1;
  27. }
  28.  
  29. var prevImg = function() {
  30. var imgs = $('.image-wrapper img');
  31. var active_obj = $('.active');
  32. var prev_img = active_obj.prev();
  33. var last_img = imgs.last();
  34.  
  35. if( !imgs.first().hasClass('active')){
  36.  
  37. prev_img.css("z-index", "2")
  38. active_obj.css("z-index", "1");
  39. prev_img.fadeIn( 800, function() {
  40. active_obj.css("z-index","1");
  41. active_obj.css("display","none");
  42. active_obj.removeClass('active');
  43. prev_img.addClass('active');
  44.  
  45. });
  46. }else{
  47. last_img.css("z-index", "2");
  48.  
  49. last_img.fadeIn( 800, function() {
  50. active_obj.css("z-index","1");
  51. active_obj.css("display","none");
  52. active_obj.removeClass('active');
  53. last_img.addClass('active');
  54. });
  55. };
  56. }
  57.  
  58. var pagination_build = function () {
  59. count_of_img = $(".image-wrapper img").length;
  60. console.log(count_of_img);
  61. for(i=0; i<count_of_img; i++){
  62. $(".pagination").append('<div class="page_el pid_'+i+'"></div>');
  63.  
  64. }
  65. }
  66.  
  67. var pagination_check = function(im_a, pa_a, im, pa) {
  68. for(i=0; i < im.length ; i++){
  69. if( im_a[i].hasClass('active') == true ){
  70. pa_a[i].addClass('checked');
  71. }else{
  72. pa_a[i].removeClass('checked');
  73. };
  74. }
  75. }
  76.  
  77. var display_img = function(im_a,pa_a, id) {
  78. for(i=0; i<im_a.length; i++){
  79. if( pa_a[i].hasClass(id)){
  80. im_a[i].fadeIn(800);
  81. im_a[i].addClass("active");
  82. pa_a[i].addClass("checked");
  83.  
  84. }else{
  85. im_a[i].css("z-index","0");
  86. im_a[i].css("display","none");
  87. im_a[i].removeClass("active");
  88. pa_a[i].removeClass("checked");
  89. }
  90. }
  91. }
  92.  
  93.  
  94. $(document).ready( function(){
  95.  
  96. pagination_build();
  97.  
  98. var img_arr = [];
  99. var pag_arr = [];
  100. var imgs = $(".image-wrapper img");
  101. var pags = $(".pagination div");
  102.  
  103. imgs.each( function(){
  104. img_arr.push($(this));
  105. });
  106. pags.each( function(){
  107. pag_arr.push($(this));
  108. });
  109.  
  110. for(i=0; i < imgs.length ; i++){
  111. img_arr[i].addClass("id_" + i);
  112. }
  113.  
  114. $("a.right").click( function(){
  115. nextImg();
  116. setTimeout(function(){
  117. pagination_check(img_arr, pag_arr, imgs, pags);
  118. },900);
  119. });
  120. $("a.left").click( function(){
  121. prevImg();
  122. setTimeout(function(){
  123. pagination_check(img_arr, pag_arr, imgs, pags);
  124. },900);
  125. });
  126.  
  127.  
  128. pagination_check(img_arr, pag_arr, imgs, pags);
  129.  
  130. var clicked_obj_name;
  131.  
  132. $(".page_el").click( function(event){
  133. clicked_obj_name = event.target.className;
  134. console.log(clicked_obj_name);
  135. display_img(img_arr,pag_arr,clicked_obj_name);
  136.  
  137. });
  138.  
  139.  
  140. ticker = setInterval( function(){
  141. pagination_check(img_arr, pag_arr, imgs, pags);
  142. nextImg();
  143. pagination_check(img_arr, pag_arr, imgs, pags);
  144. }, 5000 );
  145.  
  146. });
Divinity
Garść nocnych uwag wink.gif

1. Dla bloku obejmującego cały slider użyłbym na Twoim miejscu ID (id="wrapper") i później przy wyszukiwaniu elementów w DOM korzystał z kontekstu. W efekcie przyspieszy to skrypt, bo raz, że samo znalezienie kontekstu będzie dla silnika JavaScript szybkie, bo jQuery skorzysta z natywnej metody getElementById(), a dwa, że każde kolejne przeszukiwanie będzie przeprowadzane w obrębie kontekstu. Przykład poniżej:

Kod
var context = $('wrapper');
var imgs = $('.image-wrapper img', context);


2. Korzystaj z chaining'u, większość metod jQuery zwraca przetworzony zbiór. Dla jasności:

Kod
// Zamiast pisać tak:
active_obj.css("display","none");
active_obj.removeClass('active');

// Możesz napisać tak:
active_obj.css("display","none").removeClass('active');


3. Dla metody .css() przy większej ilości parametrów przekazuj obiekt. Przykład:

Kod
//Zamiast
active_obj.css("z-index","1");
active_obj.css("display","none");

// Możesz zapisać tak:
active_obj.css( { "z-index":"1", "display" :"none" });


4. Przechowuj w zmiennej długość tablicy, po której iterujesz. Dzięki temu pętla za każdym razem nie będzie musiała przeliczać długości tablicy. Ewentualnie jeżeli masz możliwość możesz korzystać z pętli while i odliczać do 0 (porównywanie z 0 będzie szybsze).

Kod
// Zamiast:
for(i=0; i < imgs.length; i++){..}

// Zapisuj tak:
var arrLenght = imgs.length;
for(i=0; i < arrLenght; i++){ ... }


5. Unikaj tego typu kodu:
Kod
for(i=0; i<count_of_img; i++){
      $(".pagination").append('<div class="page_el pid_'+i+'"></div>');
}

Generalnie przeszukiwanie DOM jest mocno kosztowne. Lepiej zrobić tak, że w pamięci tworzysz sobie jakiś element i w pętli append'ujesz do niego kolejne elementy. A dopiero poza pętlą dodajesz to do drzewa DOM.

6. Ten fragment jest zupełnie niepotrzebny. Metoda .each() działa na zbiorach jQuery więc niepotrzebnie przenosisz zbiór do nowej tablicy.

Kod
    var img_arr = [];  

    var pag_arr = [];

    var imgs = $(".image-wrapper img");

    var pags = $(".pagination div");



    imgs.each( function(){

      img_arr.push($(this));

    });

    pags.each( function(){

      pag_arr.push($(this));

    });



    for(i=0; i < imgs.length; i++){

      img_arr[i].addClass("id_" + i);

    }


7. Ogólnie masz trochę powtórzeń w kodzie. Postaraj się je wyeliminować ;].

8. Jeżeli piszesz to jako plugin jQuery to możesz skorzystać z wzorca pluginów. Zdaje mi się, że na stronie jQuery jest gdzieś przykład w jaki sposób je pisać. Weź pod uwagę dodanie obiektu konfiguracyjnego, dzięki któremu przy odpaleniu slidera będzie możliwe skonfigurowanie, np. interwału zmiany obrazków.

9. W instrukcjach warunkowych korzystaj z operatora identyczności (===) zamiast równości (==).

;]
wiktorc
Wielkie dzięki!
Naprawdę pomocna i konstruktywna odpowiedz. Jeśli chodzi o przepisanie tablicy w tablice to faktycznie to było dość głupie sciana.gif Mam pytanko jeśli chodzi o punkt 7 czy moglbys mi podać przykład takiego powtórzenia, które można wyeliminować.
Wiem ze sposób oznaczania zdjęcia względem paginacji jest trochę zamieszany w tej chwili jest całkowicie zależny od timingu w sensie jeśli w jednym miejscy czas wykonania (setTimeout(), setInterval()) jest większy niż w innym zaczyna się wszystko mieszać, może jest jakiś lepszy sposób na rozwiązanie tego.
Dzięki za każdą pomoc:)
A może, jakie macie sposoby na rozwijanie swoich umiejętności? Jakie sobie stawialiście zadania podczas nauki? Z jakich pomocy korzystacie, literatura, strony internetowe(nie chodzi mi o oficjalną dokumentację)?
Divinity
Cytat
Mam pytanko jeśli chodzi o punkt 7 czy moglbys mi podać przykład takiego powtórzenia, które można wyeliminować.


W wielu miejscach umieszczasz kod manipulujący na klasach CSS i przełączający z-index. Spróbój sobie to wydzielić do osobnej metody, która wykonuje te przekształcenia. Dodatkowo, na przykład 3 razy przeszukujesz DOM zapisujac do zmiennej zbiór:

Kod
var imgs = $('.image-wrapper img'); //x2
count_of_img = $(".image-wrapper img").length;


Zdefiniuj sobie to tylko raz. Zauważyłem jeszcze, że funkcja nextImgs() zwraca 1 (return 1). To chyba też Ci nie jest potrzebne.

Poczytaj sobie o konwencjach pisania kodu JavaScript. Dla mnie trochę ciężko czyta się ten kod, do tego zmienne powinny same tłumaczyć co przechowywują, dla przykładu: im_a[i] nie mówi mi nic wink.gif. Nie jest to jakiś warunek konieczny, ale znacząco poprawi jakość kodu. Możesz jeszcze skorzystać z narzędzia JSLint.

Pozdrawiam ;]
clapton4321
Co do używania append w ciele pętli, lepiej to zrobić w następujący sposób:
  1. var x,
  2. len = 20,
  3. animArr = [];
  4. for(x=0;x<len;x +=1) {
  5. animArr[x] = '<div id="cos' + x +'"></div>';
  6. };
  7. $('jakisDiv').append(animArr);
  8.  

lub
  1. var mojedivy = "";
  2. for(x=0;x<20;x +=1) {
  3. mojedivy += '<div id="cos' + x +'"></div>';
  4. };
  5. $('jakisDiv').append(mojedivy);

Masz utworzonych np. 20 divów i teraz dodajesz tylko dla tych divów określone wartości.

Po drugie zamiast operować na klasach lepszym sposobem jest operować na indeksach.

Po trzecie zamiast each używaj szybszych pętli, jakie oferuje js.
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.