Вход

Просмотр полной версии : jQuery Image Loading


Kyjek
06.06.2017, 09:33
Доброго времени суток дорогие разработчики.
Пытаюсь создать слайдер. Идея заключается в том, чтобы картинки, используемые в слайдере, загружались не сразу, а только перед их запросом на отображение.
Контейнер для картинки имеет следующий вид:

<div class="slide" id="img1" data-img="img/slide-img/img (0).jpg"></div>

id="img1" - используется только для примера.
data-img="img/slide-img/img (0).jpg" - url изображения
для загрузки мне необходимо отловить события:
1. Загрузки (поместить в div индикатор загрузки )

<i class="fa fa-spinner fa-spin fa-2x" style="display:block;" aria-hidden="true"></i>

2. Ошибки (поместить в div индикатор ошибки )

<i class="fa fa-exclamation-triangle fa-2x" style="display:block;" aria-hidden="true"></i>

3. Готово (Все загрузилось, поместить загруженную картинку в div)

$('#img1').append(image);

Для примера возьмем событие для загрузки: «нажатие на блок».
Добавим обработчик в документ реаду

$('#img1').click(function () {
var url = $('#img1').data('img');
$.when(load_img_async(url)).done(function (image)
{
$('#img1').append(image);
});
});

Вытащим url и подставим его в функцию load_img_async, дождемся когда она выполнится. После чего запихнем картинку в div как написано в пункте 3.
Код функции

function load_img_async(source) {
return $.Deferred(function (task) {
var image = new Image();
image.onload = function ()
{
$('#img1').empty();
task.resolve(image);
}
image.onerror = function ()
{
$('#img1').empty().append('<i class="fa fa-exclamation-triangle fa-2x" style="display:block;" aria-hidden="true"></i>');
task.reject();
}
$('#img1').empty().append('<i class="fa fa-spinner fa-spin fa-2x" style="display:block;" aria-hidden="true"></i>');
image.src = source;
image.className = "slide-img";
}).promise();
}

Функция создает объект image и вешает два обработчика событий оnload все загружено и onerror ошибка. Далее наш div чистим и помещаем в него fa-spinner. Если ошибка то div чистим и помещаем в него fa-exclamation. Если же оnload все загружено то чистим div и возвращаем готовое изображение, которое будет помещено в этот же div.
Вроде все хорошо и работает, но я беру большую картинку (40мб). И вставляю ее. Загрузка происходит быстро ( ведь лежит в той же папке), но вот ее отрисовка происходит полосками. Предполагаю что $('#img1').append(image); кидает ее в контейнер и да она загружена, но не отрисованна и медленно появляется в контейнере.
Как отловить время отрисовки?
P.s. хотелось бы еще реализовать плавную смену индикатора загрузки, ошибки и картинки в diю
Моя маленькая прихоть получить % или kb загрузки картинки.
Готов рассмотреть другой подход к загрузке изображений. Спасибо всем кто откликнется!

Kyjek
06.06.2017, 13:21
Спасибо.
Пример http://jsfiddle.net/4fg3K/34/ не работает как надо. Он так же как и мой код пропускает отрисовку.

function checkIfRendered(img, onRender) {
var elRatio = img.width() / img.height();
var natRatio = img.naturalWidth / img.naturalHeight;

if (elRatio === natRatio)
onRender();
else {
setTimeout(function() {
checkIfRendered(img, onRender)
}, 20);
}
}

img.onload(checkIfRendered(img, function() { alert('rendered!'); }));

Вообще крашится на получении ширины экрана. Я если честно даже не понимаю почему.
Но люди же как то получают рисуют % загрузки фото, как это сделать?

Kyjek
06.06.2017, 13:59
Потому что когда я ищу плагины загрузки изображений, они как то получают и % и картинки показываются только после полной отрисовки.

Но Вы правы эток делу не относится.

Kyjek
06.06.2017, 14:30
Я вижу связь. Что картинка уже вся загрузилась и я теряю над ней всяческий контроль. событие onload произошло и все весь js считает что картинка загрузилась. То что она долго отрисовывается на экране это уже не проблема сети браузера и т.д. это полностью клиенская задача. Маленькие картинки не имеют таких проблем, да и использовать я буду восновном их, не более 100-400KB.
Что касается сторонних то например в lazyload картинка не отображается пока полностью не отрисуется, в дурацких так же как и у меня вылезает по строчкам.
Возможно стронние скрипты имеют более сложный функционал. За счет чего они этого добиваются.

Kyjek
06.06.2017, 14:33
Работает как надо на ура

<img class="lazy" data-original="img/1.jpg" style="width:100%;" >
<script src="jquery-2.2.4.js"></script>
<script src="jquery.lazyload.js?v=1.9.1"></script>
<script type="text/javascript" charset="utf-8">
$(function() {
$("img.lazy").lazyload();
});
</script>

Kyjek
06.06.2017, 15:07
https://jsfiddle.net/Kyjek/ut4xmk56/1/

Да на глаз. При больших обьемах это видно. Открытого Коллбэка нет поэтому меня и не устраивает этот скрипт.

Kyjek
06.06.2017, 15:14
https://jsfiddle.net/Kyjek/ut4xmk56/5/

изменил на огромное фото http://luxfon.com/images/201505/luxfon.com_35100.jpg
оно очень долго рисуется.

Собсвенное весь код перед глазами. но что он делает я сходу не пойму ))

Kyjek
06.06.2017, 16:03
Чего же тут не понять. Картинка в примере https://jsfiddle.net/Kyjek/ut4xmk56/5/
отображается сразу полностью. от верха до низа. не полосками (по полсочке). Мне надо понять как. Код есть но сложный. Совственно это все.

трафик в 2017 году. сейчас даже на мобильном безлимитный. Покрайнемере у меня :)

Kyjek
07.06.2017, 10:39
Проанализировал код lazy плагина и выделил часть отвечающую за прорисовку.
Реализованно хитро и совсем не гибко.
<img id="img1" data-original="img/2.jpg" src="img/loader.gif" >
Есть картинка с изначальной img/loader.gif и пока img/2.jpg не загрузится и не прорисуется она не сменит img/loader.gif.

$(document).ready(function () {
var $self = $('#img1');
$self.one("appear", function () {
var original = $self.data('original');
$("<img />")
.bind("load", function () {
$self.attr("src", original);

})
.attr("src", original);
}).trigger("appear");
});

Надо заметить что работает так как мне нужно, но я не могу отловить момент когда происходит смена картинки.
Я бы хотел добавить стиль к загруженной картинке. (например width:100%;)
Но так не получается стиль применяется раньше и раздувает img/loader.gif.
Подскажите как отловить событие смены картинок и если можно немного пояснните как загружается изображение.

laimas
07.06.2017, 11:11
.attr("src", original) - старт загрузки
.bind("load"... - окончание загрузки
$self.one("appear"... определение момента загрузки (прокручено до изображения, "ленивая загрузка")

Kyjek
07.06.2017, 15:26
этот колбэк выполняется раньше чем картинка сменится. Т.е. он выполняется по факту загрузки.
Если смотреть код в отладчике, проходя по всем шагам, то можно заметить что все выполнение js заканчивается на этапе замены src. Дальше js ничего не делает, однако на экране у картинки с прописанным src = img ( он подставился туда т.к. load произошел) отображается загрузчик и он сам сменится на картинку как только она прорисуется. Это какая то хитрость на которой основана работа плагина. Меня она полностью устраивает за исключением одного.
Я хочу изменить заглушку загрузки.
Тут она хитрая

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAA fFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJc EhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC

Такая короткая по объёму и в тоже время бесконечно длинная картинка в виде квадрата. Что это такое???
В идеале хотелось бы ее с spiner в центре.
но будет достаточно сделать ее не в виде квадрата, а прямоугольник с короткой высотой, т.к. в большинстве случаев картинке задается ширина, а высота автоматически, что делает неудобным применение данной заглушки.

Kyjek
07.06.2017, 17:11
Хм прикольно, можете подсказать как сделать два пикселя в ряд прозрачных! В base64