Я пишу Javascript, чтобы изменить размер большого изображения в соответствии с размером окна браузера пользователя. (К сожалению, я не контролирую размер исходных изображений.)
В HTML будет что-то вроде этого:
<img id = "photo"
src = "a_really_big_file.jpg"
alt = "this is some alt text"
title = "this is some title text" />
Есть ли способ определить, был ли загружен образ src в теге img?
Мне это нужно, потому что я сталкиваюсь с проблемой, если $(document).ready() выполняется до того, как браузер загрузит изображение. $("#photo").width() и $("#photo").height() вернут размер заполнителя (альтернативный текст). В моем случае это что-то вроде 134 x 20.
Прямо сейчас я просто проверяю, меньше ли высота фотографии 150, и предполагаю, что если да, то это просто замещающий текст. Но это настоящий взлом, и он сломается, если высота фотографии меньше 150 пикселей (что маловероятно в моем конкретном случае), или если высота альтернативного текста больше 150 пикселей (возможно, это произойдет в небольшом окне браузера) .
Редактировать: Для всех, кто хочет увидеть код:
$(function()
{
var REAL_WIDTH = $("#photo").width();
var REAL_HEIGHT = $("#photo").height();
$(window).resize(adjust_photo_size);
adjust_photo_size();
function adjust_photo_size()
{
if (REAL_HEIGHT < 150)
{
REAL_WIDTH = $("#photo").width();
REAL_HEIGHT = $("#photo").height();
if (REAL_HEIGHT < 150)
{
//image not loaded.. try again in a quarter-second
setTimeout(adjust_photo_size, 250);
return;
}
}
var new_width = . . . ;
var new_height = . . . ;
$("#photo").width(Math.round(new_width));
$("#photo").height(Math.round(new_height));
}
});
Обновлять: Спасибо за предложения. Существует риск того, что событие не будет запущено, если я установлю обратный вызов для события $("#photo").load, поэтому я определил событие onLoad непосредственно в теге изображения. Для записи вот код, который я выбрал:
<img id = "photo"
onload = "photoLoaded();"
src = "a_really_big_file.jpg"
alt = "this is some alt text"
title = "this is some title text" />
Затем в Javascript:
//This must be outside $() because it may get called first
var isPhotoLoaded = false;
function photoLoaded()
{
isPhotoLoaded = true;
}
$(function()
{
//Hides scrollbars, so we can resize properly. Set with JS instead of
// CSS so that page doesn't break with JS disabled.
$("body").css("overflow", "hidden");
var REAL_WIDTH = -1;
var REAL_HEIGHT = -1;
$(window).resize(adjust_photo_size);
adjust_photo_size();
function adjust_photo_size()
{
if (!isPhotoLoaded)
{
//image not loaded.. try again in a quarter-second
setTimeout(adjust_photo_size, 250);
return;
}
else if (REAL_WIDTH < 0)
{
//first time in this function since photo loaded
REAL_WIDTH = $("#photo").width();
REAL_HEIGHT = $("#photo").height();
}
var new_width = . . . ;
var new_height = . . . ;
$("#photo").width(Math.round(new_width));
$("#photo").height(Math.round(new_height));
}
});
@ jon.wd7: я не знаком с этим плагином, и, возможно, его не было еще в '08. что касается max-width и max-height, две вещи: 1) они не поддерживаются в IE (ну, насчет IE 8 я не уверен); 2) если окно просмотра меняет размер (размер окна изменяется и т. д.), Мне все равно понадобится javascript, чтобы изменить максимальную ширину / максимальную высоту (хотя я не могу, если бы я использовал «100%», а не измерение в пикселях)
Согласно quirksmode.org, он определенно поддерживается в IE7 и IE8. Так что я не уверен в вашей проблеме. Я лично не поддерживаю IE6 для подобных мелочей, поэтому они увидят то же самое, что увидит пользователь без включенного JS. И, конечно же, вам нужно будет сбросить max-width и max-height при изменении размера. Но это довольно простая задача, фактически однострочная с использованием .resize().
Свойство полный дает обязательный способ узнать, загружено ли изображение.
@incarnate Я не согласен. Поскольку свойство complete элемента изображения явно не поддерживается: невозможно найти надежный источник информации о поддержке браузером. Это единственное упоминание об этом в спецификации HTML5, и на момент написания она все еще находится в черновой версии. см. единственную спецификацию, касающуюся "полного" свойства w3.org/html/wg/drafts/html/master/…, а Mozilla показывает поддержку свойства "complete" как неизвестное developer.mozilla.org/en/docs/Web/API/HTMLImageElement
Библиотека javascript imagesloaded отлично справляется с этой задачей. См. stackoverflow.com/questions/1977871/…
@Adrien, Mozilla теперь показывает завершена, поскольку поддерживается всеми основными браузерами, кроме Andoid (неизвестно).



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Либо добавьте прослушиватель событий, либо заставьте изображение объявить о себе с помощью onload. Затем определите размеры оттуда.
<img id = "photo"
onload='loaded(this.id)'
src = "a_really_big_file.jpg"
alt = "this is some alt text"
title = "this is some title text" />
Согласно спецификации, onload - это только событие для элементов body и frameset; Тем не менее, я думаю, что это работает в IE, но я не знаю, работает ли это в каких-либо других браузерах или что вы можете предположить, что это то, что вы можете предположить ... Я только что изучал это пару недель назад ...
Я тестировал его в IE6, IE7, FF3, Opera9, Safair (Windows Beta) и Chrome (Windows Beta).
Беспорядочное поведение и контент не приветствуются. События следует применять с использованием Javascript, а не HTML.
Его комментарий актуален, поскольку мы не застряли в 2008 году. Люди все еще читают это, и даже если это не считалось плохой практикой в 08, вы не хотите, чтобы люди думали, что это хорошая практика сейчас.
Итак, какое сейчас лучшее решение или передовой опыт в 2013 году .... @MathiasMadsenStav
Я думаю, что кто-то должен дать лучший ответ на этот вопрос, который поможет другим, я знаю, что на этот вопрос уже есть правильный ответ, но я надеюсь, что они могут быть лучше ответом без беспорядочного поведения и содержимого с использованием java script или jquery :):) ... просто мысль ..... @ dionyziz
document.querySelector ("img"). addEventListener ("load", function () {alert ('onload!');});
Попробуйте что-нибудь вроде:
$("#photo").load(function() {
alert("Hello from Image");
});
Спасибо. Однако существует вероятность того, что изображение уже было загружено до того, как это произойдет, и в этом случае событие загрузки не будет запущено.
Как насчет тега сценария, устанавливающего это событие сразу после тега изображения? Причина использования ready - убедиться, что загружен весь документ, что в данном случае не нужно, верно?
Вы хотите сделать то, что сказал Аллен, однако имейте в виду, что иногда изображение загружается до готовности dom, что означает, что ваш обработчик нагрузки не срабатывает. Лучше всего сделать так, как говорит Аллен, но установить src изображения с помощью javascript после присоединения обработчика нагрузки. Таким образом, вы можете гарантировать, что он сработает.
Что касается доступности, будет ли ваш сайт работать для людей без JavaScript? Вы можете указать тегу img правильный src, прикрепить обработчик dom ready для запуска вашего js: очистить изображение src (установить фиксированное значение с помощью и высоту с помощью css, чтобы предотвратить мерцание страницы), затем установите обработчик загрузки img, затем сбросьте src на правильный файл. Таким образом вы охватите все базы :)
Сайт по-прежнему работает для людей без Javascript, им просто нужно прокрутить, чтобы увидеть все изображение.
Есть комментарии по этому поводу?
...
doShow = function(){
if ($('#img_id').attr('complete')){
alert('Image is loaded!');
} else {
window.setTimeout('doShow()',100);
}
};
$('#img_id').attr('src','image.jpg');
doShow();
...
Вроде везде работает ...
использование setTimeout - плохая практика
Правильный ответ - использовать event.special.load
It is possible that the load event will not be triggered if the image is loaded from the browser cache. To account for this possibility, we can use a special load event that fires immediately if the image is ready. event.special.load is currently available as a plugin.
Согласно документам на .нагрузка()
Я собирался добавить ответ с таким предложением, рад, что увидел этот ответ, прежде чем его кодировать. По сути, ваши обработчики должны сначала проверить, загружено ли изображение, прежде чем устанавливать обработчик. Если он уже загружен, немедленно активируйте обратный вызов. Это то, что делает $.ready. Я собирался предложить просто проверить ширину, но в этом есть свои проблемы, мне очень нравится это решение.
Используя хранилище данных jquery, вы можете определить «загруженное» состояние.
<img id = "myimage" onload = "$(this).data('loaded', 'loaded');" src = "lolcats.jpg" />
Тогда в другом месте вы можете сделать:
if ($('#myimage').data('loaded')) {
// loaded, so do stuff
}
Используйте jQuery(this) вместо $(this) для лучшей совместимости с другими библиотеками (jquery не владеет $), особенно если у вас есть JavaScript в html.
Я только что создал функцию jQuery для загрузки изображения с помощью Отложенный объект jQuerys, что позволяет очень легко реагировать на событие загрузки / ошибки:
$.fn.extend({
loadImg: function(url, timeout) {
// init deferred object
var defer = $.Deferred(),
$img = this,
img = $img.get(0),
timer = null;
// define load and error events BEFORE setting the src
// otherwise IE might fire the event before listening to it
$img.load(function(e) {
var that = this;
// defer this check in order to let IE catch the right image size
window.setTimeout(function() {
// make sure the width and height are > 0
((that.width > 0 && that.height > 0) ?
defer.resolveWith :
defer.rejectWith)($img);
}, 1);
}).error(function(e) {
defer.rejectWith($img);
});
// start loading the image
img.src = url;
// check if it's already in the cache
if (img.complete) {
defer.resolveWith($img);
} else if (0 !== timeout) {
// add a timeout, by default 15 seconds
timer = window.setTimeout(function() {
defer.rejectWith($img);
}, timeout || 15000);
}
// return the promise of the deferred object
return defer.promise().always(function() {
// stop the timeout timer
window.clearTimeout(timer);
timer = null;
// unbind the load and error event
this.off("load error");
});
}
});
Использование:
var image = $('<img />').loadImg('http://www.google.com/intl/en_com/images/srpr/logo3w.png')
.done(function() {
alert('image loaded');
$('body').append(this);
}).fail(function(){
alert('image failed');
});
Смотрите, как это работает: http://jsfiddle.net/roberkules/AdWZj/
Звучит замечательно. Не могли бы вы привести точный пример того, когда ваш код предпочтительнее img.onload и img.onerror? Ваш код предназначен только для обработки кажущихся недостатков обработки ошибок jQuery, о которых я только что был проинформирован: эта ошибка не запускается в IE, если нет расширения файла?
интересная идея. так что зная, когда изображение стало проще. Но что, если изображение не может быть загружено. Я искал способ узнать, не удалось ли загрузить изображение. и вы дали мне идею тайм-аута при его загрузке. +1 за это
@oak тайм-аут должен быть только запасным вариантом. большинство браузеров должны запускать событие error, которое обрабатывается .error(function(e) { defer.rejectWith($img); }). Если вы посмотрите на jsFiddle, вы увидите, что текст http://www.google.com/abc.png not found отображается сразу в панели результатов (не дожидаясь тайм-аута, потому что произошло событие ошибки)
обратите внимание, что для того, чтобы jquery поднял .error, должны быть две вещи: 1. дескриптор, но они должны быть установлены до возникновения ошибки. 2. .error обрабатывает только протокол http, а не file: //, поэтому вы не получите там ошибки ..
в моем примере кода обработчик успеха / ошибки устанавливается перед назначением атрибута src именно по этой причине. насчет ограничения file:// - мне никогда не нужно было связывать изображения с использованием файлового протокола, и я не думаю, что в этом особая необходимость.
Эта функция проверяет, загружено ли изображение, исходя из измеримых размеров. Этот метод полезен, если ваш сценарий выполняется после того, как некоторые изображения уже были загружены.
imageLoaded = function(node) {
var w = 'undefined' != typeof node.clientWidth ? node.clientWidth : node.offsetWidth;
var h = 'undefined' != typeof node.clientHeight ? node.clientHeight : node.offsetHeight;
return w+h > 0 ? true : false;
};
Я обнаружил, что для этого решения может потребоваться, чтобы на изображении не было полей или отступов, а также был предоставлен альтернативный текст пустой строки. Однако в большинстве случаев это работает так, как задумано. Он потерпит неудачу только в том случае, если размер выгруженного изображения больше нуля.
Существует плагин jQuery под названием «imagesLoaded», который предоставляет кроссбраузерный метод проверки, загружены ли изображения элемента.
Сайт: https://github.com/desandro/imagesloaded/
Использование контейнера, внутри которого много изображений:
$('container').imagesLoaded(function(){
console.info("I loaded!");
})
Плагин отличный:
кажется довольно тяжелым 5 КБ, уменьшенным только для проверки загруженного img. Должен быть доступный более простой способ зажигалки ...
Согласно одному из недавних комментариев к вашему исходному вопросу
$(function() {
$(window).resize(adjust_photo_size);
adjust_photo_size();
function adjust_photo_size() {
if (!$("#photo").get(0).complete) {
$("#photo").load(function() {
adjust_photo_size();
});
} else {
...
}
});
Предупреждение Этот ответ может вызвать серьезный цикл в IE8 и ниже, потому что img.complete не всегда правильно устанавливается браузером. Если вы должны поддерживать ie8, используйте флаг, чтобы запомнить, что изображение загружено.
Погоди. Этот ответ может вызвать серьезный цикл в IE8 и ниже, потому что img.complete не всегда правильно устанавливается браузером. Если вы должны поддерживать ie8, используйте флаг, чтобы запомнить, что изображение загружено.
Я обнаружил, что это сработало для меня
document.querySelector("img").addEventListener("load", function() { alert('onload!'); });
Кредит полностью принадлежит Фрэнку Швитерману, который прокомментировал принятый ответ. Пришлось положить сюда, слишком ценно ...
Мы разработали страницу, на которую загружалось несколько изображений, а другие функции выполнялись только после того, как изображение было загружено. Это был загруженный сайт, который генерировал много трафика. Похоже, что следующий простой скрипт работал практически во всех браузерах:
$(elem).onload = function() {
doSomething();
}
НО ЭТО ПОТЕНЦИАЛЬНАЯ ПРОБЛЕМА ДЛЯ IE9!
ЕДИНСТВЕННЫЙ браузер, о котором мы сообщали о проблемах, - это IE9. Мы не удивлены? Кажется, что лучший способ решить проблему - не назначать src изображению до тех пор, пока ПОСЛЕ определения функции onload, например:
$(elem).onload = function() {
doSomething();
}
$(elem).attr('src','theimage.png');
Кажется, что IE 9 иногда не генерирует событие onload по какой-либо причине. Другие решения на этой странице (например, от Эвана Кэрролла) по-прежнему не работали. Логически это проверяет, было ли состояние загрузки уже успешным, и запускает функцию, а если нет, то устанавливает обработчик загрузки, но даже когда вы это делаете, мы продемонстрировали при тестировании, что изображение может загружаться между этими двумя строками js, тем самым отображается не загруженным в первую строку, а затем загружается до того, как будет установлен обработчик загрузки.
Мы обнаружили, что лучший способ получить желаемое - не определять src изображения до тех пор, пока вы не установите триггер события onload.
Мы совсем недавно прекратили поддержку IE8, поэтому я не могу говорить о версиях до IE9, в противном случае из всех других браузеров, которые использовались на сайте - IE10 и 11, а также Firefox, Chrome, Opera, Safari и т. д. люди использовали мобильный браузер - установка src перед назначением обработчика onload даже не была проблемой.
Могу я вообще предложить решение на чистом CSS?
Просто имейте Div, в котором вы хотите показать изображение. Установите изображение в качестве фона. Тогда имейте свойство background-size: cover или background-size: contain в зависимости от того, как вы этого хотите.
cover будет обрезать изображение до тех пор, пока меньшая сторона не закроет коробку.
contain сохранит все изображение внутри div, оставляя вам пробелы по бокам.
Проверьте фрагмент ниже.
div {
height: 300px;
width: 300px;
border: 3px dashed grey;
background-position: center;
background-repeat: no-repeat;
}
.cover-image {
background-size: cover;
}
.contain-image {
background-size: contain;
}<div class = "cover-image" style = "background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)">
</div>
<br/>
<div class = "contain-image" style = "background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)">
</div>Я считаю, что мне лучше всего подходит это простое решение:
function setEqualHeight(a, b) {
if (!$(a).height()) {
return window.setTimeout(function(){ setEqualHeight(a, b); }, 1000);
}
$(b).height($(a).height());
}
$(document).ready(function() {
setEqualHeight('#image', '#description');
$(window).resize(function(){setEqualHeight('#image', '#description')});
});
</script>
Это так давно, и вы уже приняли ответ, поэтому я просто прокомментирую здесь. Почему вы не можете использовать плагин jQuery onImagesLoad? А также, jQuery или нет, что не так с настройкой
max-widthиmax-heightв стиле изображения с помощью Javascript? Затем вы избегаете ВСЕГО кода, который вам нужно написать, устанавливая максимальную ширину / высоту равной размеру ширины / высоты области просмотра.