Чтобы отследить момент загрузки картинки одного обработчика события « load» бывает не достаточно. Если он будет прикреплен к картинке после того, как она уже была загружена, то событие больше не повторится и обработчик не будет вызван.
Поможет решить эту проблему вспомогательный плагин к jQuery.
;(function ($) {
$.fn.bindImageLoad = function (callback) {
function isImageLoaded(img) {
// Во время события load IE и другие браузеры правильно
// определяют состояние картинки через атрибут complete.
// Исключение составляют Gecko-based браузеры.
if (!img.complete) {
return false;
}
// Тем не менее, у них есть два очень полезных свойства: naturalWidth и naturalHeight.
// Они дают истинный размер изображения. Если какртинка еще не загрузилась,
// то они должны быть равны нулю.
if (typeof img.naturalWidth !== "undefined" && img.naturalWidth === 0) {
return false;
}
// Картинка загружена.
return true;
}
return this.each(function () {
var ele = $(this);
if (ele.is("img") && $.isFunction(callback)) {
ele.one("load", callback);
if (isImageLoaded(this)) {
ele.trigger("load");
}
}
});
};
})(jQuery);
Обновление: Работу плагина можно посмотреть в примере. Там используется немного модифицированная версия, которая формирует специальное событие.
Коментарии к заметке
очень пригодилось, спасибо
Как юзать не понятно
Используется как любой другой плагин jQuery.
Чаще всего такое событие нужно для предварительной загрузки больших картинок в кеш браузера, чтобы их в последствии можно было сразу показать пользователю.
Есть один нюанс в ситуации, когда нужно получить размер картинки сразу после её загрузки. Все браузеры, кроме Safari и Chrome, могут получить правильные значения в функции обратного вызова. Для них нужно делать небольшую паузу.
…Я не смог найти Ваш плагин в нете. Это вы его и написали сами? Если да,то какие условия его использования в МОЕМ коде?
andrew, плагин писал сам. Вы можете свободно использовать его в любых проектах и модифицировать для конкретных нужд, если потребуется.
Огромнейшее спасибо, Владимир!
Я сделал галерею, пока показать не могу, но мне кажется,что он не ловит размеры картинки в мозилле. Я так был рад что все работает! Но я тестил на Опере. А потом переключился на ФФ и все стало как обычно — картинка пока сырая, хоть и появляется на экране не отдает своих размеров . Отсюда смещения влево-вправо при 1-й загрузке. А потом все нормально-из кеша достает. Я видел в Ваших коментах за ГЕКО браузеры. Вот бы такое по-всюду! Сначала отдает размеры , а потом пусть себе появляеться в уже подготовленном для ее месте. Я думаю,что плагин для этого и делался…
вот оперу показываю с Вашим плагином. Тут все чисто http://www.youtube.com/watch?v=Aa2-cFPGukM&feature=player_embedded#!
Плагин отлично ловит размеры изображения еще до его появления на экране, а ФФ не хочет. Пришлось делать по-старинке
Оперу спасает на отлично, а ФФ …
я хотел сказать с timeOut-по старинке. Лоад работает единожды. видимо придеться переключать функции или скрипты в зависимости от браузера
andrew, не совсем понял из комментариев в чем проблема. Попробуйте сделать отдельную не слишком навороченную страничку и протестировать её во всех браузерах. Мне кажется, что беда где-то скрылась в другом участке кода и не имеет отношения к проверке на загруженность картинки.
Плагин bindImageLoad, по своей сути, является оберткой над load, но с дополнительными проверками. Если обычный load работает, то bindImageLoad тем более будет работать в этом месте.
Меня смущает то, что в примере вы задаете атрибут
src
и ждете загрузку какого-то объекта, который уже находится на странице. Наверное в этом и кроется проблема. Теоретически, объект-картинка должна создаваться каждый раз заново и только потом добавляться на страницу (смотрите мои примеры выше).В тег эс-ер-це тега попадает содержимое ячейки таблици при моусентер-событии на ячейке. …Ничего сложного в коде, по сути… У меня уже и лоад заработал КАЖДЫЙ раз при появлении картинки, ПОЧТИ, как Ваш плагин. Но только, ПОЧТИ.
Ваш плагин в части моего нехитрого кода в Опере выдает картинку так же быстро, как это бы было при клике на ссылку. А при ПРОСТОМ лоад, превая загрузка происходит с паузой в пол-секунды. Сначала, фон-потом картинка. Так как я не знаю в чем дело (я и Ваш код правил даже), то я просто напишу 2 версии плагина — по штуке на оперу/ИЕ с Вашим лоад и отдельно для ФФ, со стандартным, пусть даже с задержкой… Но хотелось бы знать от чего та задержка появления картинки при 1 загрузке происходит. Я обратил внимание, что просмотрщики типа ФЕНСИ Бокса и др. могут маскировать этот дефект анимацией.
Можно узнать разницу между
$("img")
и$("<img/>")
? Много раз встречал такое… Это аналог КриеэйтЭлемент из чистого ДжЭс?Если да, то тогда в
$(this).appendTo("div.block");
нужно предусмотреть стирание предшествующих добавленных?…По скрипту у меня в тег ИМИДЖ в атрибут ЭС-ЭР-ЦЕ внедряется текст с ячейки таблицы при моусэнтере на ней.
Разметка такая: тег ДИВ — тег ИМИДЖ — конец тега ДИВ. От РАЗМЕТКИ такая пауза и некорректность и некорректность работы в целом? Мне нужно создавать а потом стирать объект имидж при каждом новом рисунке? Если да, то стоит плагин по созданию элементов подключать?
Задержка появления картинки при первом использовании вполне логична. Пока картинка передается по сети, в браузере ничего не будет отображаться. Когда картинка уже хоть раз загружалась, то она берется из кеша браузера и появляется практически мгновенно. Можно делать предварительную загрузку картинок, чтобы потом быстро показывать их.
Совершенно верно. Первое выражение ищет тег img, а вторая — создает новый тег, который нужно потом еще будет добавить в документ.
Да.
Еще раз. Менять атрибут не корректно из-за того, что элемент img уже существует, предыдущая картинка загружена и имеет какие-то размеры. По этому в Firefox
bindImageLoad
сразу сработает. Нужен совершенно новый элемент. Разметка тут совсем ни при чем.не могу сдержаться…
А ключевой элемент плагина это
img = $(this)
Наверное секретная незадокументировання деталь. Вставляешь после обычного лоадvar img = $(this)
и… О чудо!!! С другими названием var, ничего не работает!!!Ерунда какая-то. Обычное название обычной переменной. Можно её назвать как угодно.
Сяду еще раз проверю. Лично меня это сильно удивило
У меня плагин отказывается работать в ОПЕРЕ 11.52, в других браузерах все нормально.
Вышло обновление ОПЕРЫ 11.60 и теперь плагин стал работать и в ОПЕРЕ :)
Я надеюсь это не связано с прекэшом всех картинок которые планируется вывести на сайт, потому что если это галерея, а картинок, допустим 100 и более, тогда сайт просто-напросто зависнет при загрузке, особенно у людей со слабым соединением, я бьюсь уже с этой проблемой долгое время, пока не нашел толковых решений, банальная смена картинок в галерее при выборе серии, цвета и т.п. оказалась сущим адом.
Стас, конечно загружать сразу все картинки никакого резона нет. Их стоит подгрузить только, когда она должна вскоре появиться в области видимости. Если это длинная страница с прокрутой, то можно отслеживать положение скроллера и добавлять картинки по мере его перемещения. Если есть разбивка на страницы, то загружать на 1-2 страницы вперед. Очевидно, что тут нет универсального решения и нужно разбирать конкрентый случай.
Вот спасибо, за плагин, а то не понимал почему Хром находит атрибуты изображений раньше чем его размеры. FF и опера нормально отрабатывали.
а как применить этот плагтн к данным загруженым с помощью ajax? кто подскажет?
Игорь, основное применение плагина я уже описывал в комментариях выше. Оно как раз подразумевает, что путь до картинки пришёл в AJAX-запросе. Опиши подробнее свою ситуацию, чтобы можно было дать конкретный совет.
Данные я загружаю вот таким методом:
Как теперь сюда вставить вашу функцию?
Например, так:
Сначала формируем разметку без картинок, а затем добавляем в неё элементы
img
. Как только картинка будет загружена, так она плавно появится на экране.Спасибо тебе за плагин огромное!! очень выручил
Спасибо за плагин! Очень помогло :) Автору бобра и света :)
Подскажите пожалуйста. Как с помощью данного метода можно отловить ошибку загрузки. Например если ссылка на картинку окажется битой?
Олег, ошибки загрузки изображений отлавливаются через событие
error
.Напоминаю, что на события нужно подписываться до их наступления. Если подписаться после, то обработчик события никогда не будет вызван.
Отличное решение. Спасибо!