2014-04-09 4 views
0

Я искал все, где и я работал над этим часами. В принципе, у меня есть выбор Ajax для извлечения данных с веб-страницы, которая извлекает данные из базы данных. Этот код предназначен для слайд-шоу для галереи изображений. Вся функция показана ниже, однако часть, которая не работает должным образом, это две строки кода, которые получают высоту и ширину изображений.Проблема с синхронизацией AJAX с jQuery

Изображения принимаются правильно, и они отображаются в порядке (ну не совсем, но они появляются). Строки, которые запрашивают ширину и высоту изображений, возвращают 0 больше всего того времени. Вероятность того, что они вернут правильные значения, составляет 5%. Это приводит к тому, что оператор if сразу после этого всегда оценивает значение false, что делает широкие изображения за пределами края веб-страницы.

Эта проблема присутствует только в браузерах, основанных на Webkit. У браузеров, основанных на Gecko, нет этой проблемы.

Я думаю, проблема в том, что jQuery пытается запросить изображения до того, как вызов Ajax завершил свой запрос. Есть ли способ заставить jQuery ждать завершения Ajax с его запросом?

function LoadForm() { 
    GalleryDataSource = new kendo.data.DataSource({ 
     transport: { 
      read: { 
       url: BaseAPI + "/PhotosByAlbum2", 
       dataType: "json", 
       data: { "location": locationID, "ID": $.getQuery('ID') } 
      } 
     } 
    }); 

    $("#slides").kendoListView({ 
     dataSource: GalleryDataSource, 
     template: kendo.template($("#SlidesTemplate").html()) 
     }); 

    $.ajax({ 
     type: "Get", 
     contentType: "application/json; charset=utf-8", 
     url: BaseAPI + "/PhotosByAlbum2", 
     datatype: "json", 
     data: { "location": locationID, "ID": $.getQuery('ID') }, 
     success: function (d) { 
      for (var i = 0; i < d.length; i++) { 
       $('#Show').append(
        '<figure><img src="' + d[i].Path + 
        '" id="' + d[i].ID + 
        '"/><figcaption>Title: ' + d[i].Title + '<br />' + 
        'Description: ' + d[i].Description + 
        '</figcaption></figure>' 
       ); 

/*these do*/ var imgheight = $("#" + d[i].ID).height(); 
/*not work*/ var imgwidth = $("#" + d[i].ID).width(); 

       if (imgheight < "768" && imgwidth > imgheight) { 
        $("#" + d[i].ID).addClass("wideimage"); 
       } else { 
        $("#" + d[i].ID).addClass("tallimage"); 
       } 
      } 

      $('#Show').innerfade({ 
       animationtype: 'fade', 
       speed: 1050, 
       timeout: 2000, 
       type: 'sequence', 
       containerheight: '500px' 
      }); 
     } 
    }); 

    $('#back').click(function() { 
     window.location = 'Photos.aspx' 
    }); 
} 

Примечание: Я попытался с помощью $.when(*ajax call here*).done(function() {*do stuff*});. Он вел себя точно так же.

И я пробовал установить опцию async на значение false. Такое же поведение.

Я также попытался добавить обработчик события complete в вызов Ajax. Опять же, он вел себя одинаково.

+2

Если вы хотите использовать размеры изображения в расчете, вы не сможете запустить этот код до тех пор, пока изображения не будут успешно загружены. И единственный способ узнать, когда это произошло, - использовать обработчик 'onload' для самих изображений. Если ваш код сейчас работает, то это ТОЛЬКО, потому что изображения находятся в кеше браузера. Ваш код не будет работать в любом браузере, если изображения не были в кеше браузера. – jfriend00

+0

Изображения хранятся на сервере, и этот код извлекает их через Ajax и, при успешном выполнении, отображает их. Не имеет смысла, почему этот код работает 100% времени в браузерах Gecko и менее 5% времени в браузерах Webkit. –

+0

Это имеет смысл для меня. Вы НЕ извлекаете изображения самостоятельно через ajax. Вы получаете имена файлов изображений через AJAX. Затем вы создаете теги изображений, устанавливаете '.src', и браузер должен THEN загружать изображения. Вы пытаетесь затем НЕМЕДЛЕННО ссылаться на высоту и ширину. Если кешировать, некоторые браузеры быстро сделают изображения, а некоторые - нет. Если вы не кешировали, ни один браузер не будет иметь изображения. Ваш код просто написан неправильно. Вы не можете надежно получить доступ к высоте или ширине, пока тег '' не обработает обработчик 'onload', чтобы указать, что изображение теперь успешно загружено. – jfriend00

ответ

0

Как я уже сказал в своих комментариях, вам нужно дождаться загрузки изображений, прежде чем вы сможете надежно получить их ширину и установить класс, который вы хотите на них.

Вот способ перестроить свой АЯКС вызов только обрабатывать изображения, как только они были загружены, и только начать анимацию сразу все были загружены изображения и помечены соответствующим образом:

$.ajax({ 
    type: "Get", 
    contentType: "application/json; charset=utf-8", 
    url: BaseAPI + "/PhotosByAlbum2", 
    datatype: "json", 
    data: { "location": locationID, "ID": $.getQuery('ID') }, 
    success: function (d) { 
     var imagesRemaining = d.length; 
     for (var i = 0; i < d.length; i++) { 
      var img = new Image(); 
      img.src = d[i].Path; 
      img.id = d[i].ID; 
      img.onload = function() { 
       --imagesRemaining; 
       var item = $(this); 
       var imgheight = item.height(); 
       var imgwidth = item.width(); 

       if (imgheight < 768 && imgwidth > imgheight) { 
        item.addClass("wideimage"); 
       } else { 
        item.addClass("tallimage"); 
       } 

       // now see if all images are loaded now 
       // so all classes are set so we can now start the animation 
       if (imagesRemaining === 0) { 
        $('#Show').innerfade({ 
         animationtype: 'fade', 
         speed: 1050, 
         timeout: 2000, 
         type: 'sequence', 
         containerheight: '500px' 
        }); 
       } 
      }; 
      $("<figure>").append(img).append('<figcaption>Title: ' + d[i].Title + '<br />' + 
       'Description: ' + d[i].Description + '</figcaption>').appendTo("#Show"); 

     } 

    } 
}); 
+0

Спасибо. Я понимаю, о чем вы сейчас говорите. Это не мой код. Я знаю, что это ужасно и доверять мне, это хуже, чем то, что я написал. Спасибо за помощь. –

1

Как указано в комментариев, вы не можете получить доступ к высоте и ширине изображения, пока он не будет загружен. Я хотел бы сделать что-то вроде этого, чтобы прослушивать событие загрузки:

$.each(d, function (idx, item) { 
    $fig = $('<figure/>'); 
    $('<figcaption/>') 
     .html('Title: ' + item.Title + '<br />Description: ' + item.Description) 
     .appendTo($fig); 

    $('<img/>') 
     .load(function() { 
      var $this = $(this); 
      var height = $this.height(); 
      var width = $this.width(); 
      if (height < "768" && width > height) { 
       $this.addClass('wideimage'); 
      } else { 
       $this.addClass('tallimage'); 
      } 
     }).attr('id', item.ID) 
     .attr('src', item.Path) 
     .appendTo($fig); 

    $fig.appendTo('#Show'); 
}); 
+0

Вот [скрипка] (http://jsbin.com/siceviwu/1/edit), которая демонстрирует проблему (по крайней мере, до кэширования изображения). – estrar

+0

Это не мой вопрос, просто поясняющий ответ на вопрос, который вы только что подняли, с примером. :) – estrar

+0

@estrar Упс! Не смотрел достаточно внимательно. Это полезная демонстрация, спасибо. –

0

Я сделал это ... конечно, может быть лучше ...

В PHP скрипт, который работает на BaseAPI + "/ PhotosByAlbum2" ... получить ширину и высоту каждого изображения, изменить размер изображений на нужную высоту и ширину для слайд-шоу, если это необходимо, а затем поместить эти переменные в массив результатов с помощью Path, Title и Description ...

На jQuery ... прочитайте массив и отрегулируйте ширину и высоту в html ...

Смежные вопросы