Получение уведомлений, когда страница DOM загружена (но до window.onload) - PullRequest
7 голосов
/ 15 сентября 2008

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

Есть ли определенный способ сделать это во всех браузерах?

Насколько я знаю:

  • DOMContentLoaded : в Mozilla, Opera 9 и новейших веб-наборах. Это включает добавление слушателя к событию:

    document.addEventListener ("DOMContentLoaded", [функция init], false);

  • Отложенный сценарий : В IE вы можете создать тег SCRIPT с атрибутом @defer, который будет надежно загружаться только после закрытия тега BODY.

  • Опрос : В других браузерах вы можете продолжать опрос, но есть ли стандартная вещь для опроса, или вам нужно делать разные вещи в каждом браузере?

Я бы хотел иметь возможность работать без использования document.write или внешних файлов.

Это можно сделать просто через jQuery:

$(document).ready(function() { ... })

но я пишу библиотеку JS и не могу рассчитывать на то, что jQuery всегда будет там.

Ответы [ 9 ]

8 голосов
/ 15 сентября 2008

Нет кросс-браузерного метода для проверки готовности DOM - вот почему существуют такие библиотеки, как jQuery, для отвлечения неприятных маленьких кусочков несовместимости.

Mozilla, Opera и современный WebKit поддерживают событие DOMContentLoaded. IE и Safari нужны странные хаки, такие как прокрутка окна или проверка таблиц стилей. Подробные сведения содержатся в функции bindReady() в jQuery.

3 голосов
/ 16 сентября 2008

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

http://www.kryogenix.org/days/2007/09/26/shortloaded

2 голосов
/ 15 сентября 2008

Использование библиотеки, такой как jQuery, сэкономит вам бесчисленные часы несоответствий браузеров.

В этом случае с jQuery вы можете просто

$(document).ready ( function () {
    //your code here
});

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

2 голосов
/ 15 сентября 2008

YUI использует три теста для этого: для Firefox и недавнего WebKit есть событие DOMContentLoaded, которое вызывается. Для старых Safari document.readyState наблюдал, пока он не стал «загружен» или «завершен». Для IE создается тег HTML

и вызывается метод doScroll (), который должен выдавать ошибку, если DOM не готов. Источник для YAHOO.util.Event показывает специфичный для YUI код. Выполните поиск «doScroll» в Event.js.

1 голос
/ 15 сентября 2008

Просто возьмите соответствующий фрагмент кода из jQuery, Джон Ресиг (John Resig) рассмотрел большинство основ по этому вопросу уже в jQuery.

0 голосов
/ 11 марта 2013

Необычное решение для кроссбраузера, которого вы ищете ... не существует ... (представьте, что большая толпа говорит "ааааа ...").

DomContentLoaded просто ваш лучший выстрел. Вам все еще нужна техника polling для старых версий IE.

  1. Попробуйте использовать addEventListener;
  2. Если недоступно (IE, очевидно), проверьте наличие кадров;
  3. Если не кадр, прокручивать, пока не будет сгенерировано сообщение об ошибке (опрос);
  4. Если фрейм, используйте событие IE document.onreadystatechange;
  5. Для других неподдерживающих браузеров используйте старое событие document.onload.

Я нашел следующий пример кода на javascript.info , который вы можете использовать для всех браузеров:

function bindReady(handler){

    var called = false

    function ready() { 
        if (called) return
        called = true
        handler()
    }

    if ( document.addEventListener ) { // native event
        document.addEventListener( "DOMContentLoaded", ready, false )
    } else if ( document.attachEvent ) {  // IE

        try {
            var isFrame = window.frameElement != null
        } catch(e) {}

        // IE, the document is not inside a frame
        if ( document.documentElement.doScroll && !isFrame ) {
            function tryScroll(){
                if (called) return
                try {
                    document.documentElement.doScroll("left")
                    ready()
                } catch(e) {
                    setTimeout(tryScroll, 10)
                }
            }
            tryScroll()
        }

        // IE, the document is inside a frame
        document.attachEvent("onreadystatechange", function(){
            if ( document.readyState === "complete" ) {
                ready()
            }
        })
    }

    // Old browsers
    if (window.addEventListener)
        window.addEventListener('load', ready, false)
    else if (window.attachEvent)
        window.attachEvent('onload', ready)
    else {
        var fn = window.onload // very old browser, copy old onload
        window.onload = function() { // replace by new onload and call the old one
            fn && fn()
            ready()
        }
    }
}
0 голосов
/ 16 сентября 2008

Почему бы не это:

<body>  
  <!-- various content -->  
  <script type="text/javascript">  
  <!--  
    myInit();  
  -->
  </script>  
</body>  

Если я правильно понимаю, myInit будет запущен, как только браузер нажмет на страницу, которая является последней вещью в теле.

0 голосов
/ 16 сентября 2008

Использование setTimeout может работать довольно хорошо, хотя, когда он выполняется, зависит от браузера. Если вы передадите ноль в качестве времени ожидания, браузер будет запускаться, когда все «улажено».

Хорошо, что вы можете иметь их много, и вам не нужно беспокоиться о цепочке событий onLoad.

setTimeout(myFunction, 0);
setTimeout(anotherFunction, 0);
setTimeout(function(){ doSomething ...}, 0);

и т.д.

Все они будут запускаться после завершения загрузки документа или, если вы настроите его после загрузки документа, они будут выполняться после завершения выполнения сценария.

Порядок, в котором они запускаются, не определен и может изменяться между браузерами. Так что вы не можете рассчитывать на то, что myFunction будет запущен до anotherFunction, например.

0 голосов
/ 15 сентября 2008

Это работает довольно хорошо:

setTimeout(MyInitFunction, 0);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...