Img onload не работает в IE7

У меня есть img-тег в моем webapp, который использует обработчик onload для изменения размера изображения:

<img onLoad="SizeImage(this);" src="foo" >

Это отлично работает в Firefox 3, но не работает в IE7, потому что объект изображения, передаваемый функции SizeImage(), по какой-либо причине имеет ширину и высоту 0 - возможно, IE вызывает функцию до того, как она закончит загрузку?. Изучая это, я обнаружил, что у других людей была такая же проблема с IE. Я также обнаружил, что это неверно HTML 4. Это наш doctype, поэтому я не знаю, действительно ли это или нет:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Существует ли разумное решение для изменения размера изображения при его загрузке, предпочтительно в соответствии со стандартами? Изображение используется для того, чтобы пользователь мог загрузить фотографию, которая может быть практически любого размера, и мы хотим отображать ее максимум 150x150. Если ваше решение должно изменить размер серверной части изображения при загрузке, я знаю, что это правильное решение, но мне запрещено его реализовывать: (Это должно быть сделано на стороне клиента, и это должно быть сделано на дисплее.

Спасибо.

Изменить. Из-за структуры нашего приложения нецелесообразно (на грани невозможности) запустить этот script в документе onload. Я могу только разумно редактировать тег изображения и код рядом с ним (например, я мог бы добавить <script> прямо под ним). Кроме того, у нас уже есть библиотеки прототипов и EXT JS... управление предпочло бы не добавлять другое (некоторые ответы предложили jQuery). Если это можно решить с помощью этих фреймворков, это будет здорово.

Изменить 2. К сожалению, мы должны поддерживать Firefox 3, IE 6 и IE 7. Желательно также поддерживать все браузеры на основе Webkit, но поскольку наш сайт в настоящее время не поддерживает их, мы можем терпеть решения, которые работают только в Big 3.

Ответ 1

IE7 пытается изменить размер изображения до того, как дерево DOM будет полностью отображено. Вам нужно запустить его на document.onload... вам просто нужно убедиться, что ваша функция может обрабатывать передачу ссылки на элемент, который не является "этим".

В качестве альтернативы... и я надеюсь, что это не пламя преступления... jQuery делает такие вещи действительно, очень легко.

EDIT в ответ на EDIT 1:

Вы можете поместить document.onload(runFunction); в любой тег script в любом месте тела. он все равно дождитесь загрузки документа для запуска функции.

Ответ 2

Если вам не нужно поддерживать IE 6, вы можете просто использовать этот CSS.

yourImageSelector {
    max-width: 150px;
    max-height: 150px;
}

Ответ 3

Я заметил, что Firefox и Safari запускают "загрузку" событий на новые изображения независимо от того, что, но IE 6 и 7 только запускают "загрузку", если им действительно нужно получить изображение с сервера - t, если изображение уже находится в локальном кеше. Я играл с двумя решениями:

1) Каждый раз давайте образ уникальному аргументу http, который игнорирует веб-сервер, например

<img src="mypicture.jpg?keepfresh=12345" />

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

2) В моем приложении изображения, которые требуют обработчиков нагрузки, динамически вставляются JavaScript. Вместо того, чтобы просто добавлять изображение, а затем создавая обработчик, я использую этот код, который хорошо тестируется в Safari, FF и IE6 и 7.

document.body.appendChild(newPicture);
if(newPicture.complete){
    doStuff.apply(newPicture);
}else{
    YAHOO.util.Event.addListener(newPicture, "load", doStuff);
}

Я использую YUI (очевидно), но вы можете атташе обработчиком, используя все, что работает в вашей среде. Функция doStuff ожидает запустить с этим, прикрепленным к затронутому элементу IMG, поэтому я называю его стилем .apply, ваш пробег может отличаться.

Ответ 4

Код для jQuery. Но легко сделать циферблат с другими фреймворками. Действительно полезно.

var onload = function(){ /** your awesome onload method **/ };
var img = new Image();
img.src = 'test.png';

// IE 7 workarond
if($.browser.version.substr(0,1) == 7){
    function testImg(){
        if(img.complete != null && img.complete == true){ 
            onload();
            return;
        }
        setTimeout(testImg, 1000);
    }
    setTimeout(testImg, 1000);
}else{
    img.onload = onload
}

Ответ 5

То, как я буду это делать, - это использовать jQuery, чтобы сделать что-то вроде:

$(document).load(function(){
    // applies to all images, could be replaced 
    //by img.resize to resize all images with class="resize"
    $('img').each(function(){
        // sizing code here
    });
});

Но я не эксперт по javascript;)

Ответ 6

setTimeout() может быть обходным путем, если вы действительно застряли. Просто установите его на 2 или 3 секунды - или после загрузки страницы.

EDIT: вы можете взглянуть на эту статью - все это в порядке с утечками IE mem...

Ответ 7

Изменить: из-за структуры нашего приложения, это непрактично (граничит с невозможно) запустить этот script в документация.

Всегда можно добавлять обработчики к window.onload (или к любому событию), даже если другие фреймворки, библиотека или код присоединяют обработчики к этому событию.

<script type="text/javascript">
function addOnloadHandler(func) {
    if (window.onload) {
        var windowOnload = window.onload;
        window.onload = function(evt) {
            windowOnload(evt);
            func(evt);
        }
    } else {
        window.onload = function(evt) {
            func(evt);
        }
    }
}

// attach a handler to window.onload as you normally might
window.onload = function() { alert('Watch'); };

// demonstrate that you can now attach as many other handlers
// to the onload event as you want
addOnloadHandler(function() { alert('as'); });
addOnloadHandler(function() { alert('window.onload'); });
addOnloadHandler(function() { alert('runs'); });
addOnloadHandler(function() { alert('as'); });
addOnloadHandler(function() { alert('many'); });
addOnloadHandler(function() { alert('handlers'); });
addOnloadHandler(function() { alert('as'); });
addOnloadHandler(function() { alert('you'); });
addOnloadHandler(function() { alert('want.'); });
</script>

Этот ответ имеет немного отличающуюся версию моего кода addOnloadHandler(), используя attachEvent. Но я обнаружил при тестировании, что attachEvent, похоже, не гарантирует, что обработчики загорятся в том порядке, в котором вы их добавили, что может быть важно. Функция, представленная, гарантирует, что обработчики запускаются в добавленном порядке.

Обратите внимание, что я передаю evt в добавленные обработчики событий. Это не является строго необходимым, и код должен работать без него, но я работаю с библиотекой, которая ожидает, что событие будет передано обработчику onload, и этот код завершится неудачно, если я не включу его в свою функцию.

Ответ 8

Вы можете сделать что-то вроде:

var img = new Image();
img.src = '/output/preview_image.jpg' + '?' + Math.random();
img.onload = function() {
  alert('pass')
}