Чистый JavaScript-эквивалент jQuery’s $ .ready () — как вызвать функцию, когда страница / DOM готова к этому

Чистый JavaScript-эквивалент jQuery’s $ .ready () — как вызвать функцию, когда страница / DOM готова к этому

Самая простая вещь, которую нужно сделать в отсутствие фреймворка, который обеспечивает всю кросс-браузерную совместимость для вас, — это просто вызвать вызов вашего кода в конце тела. Это выполняется быстрее, чем обработчик загрузки, потому что он ожидает только готовности DOM, а не загрузки всех изображений. И это работает в любом браузере.

 {amp}lt;!doctype html{amp}gt; {amp}lt;html{amp}gt; {amp}lt;head{amp}gt; {amp}lt;/head{amp}gt; {amp}lt;body{amp}gt; Your HTML here {amp}lt;script{amp}gt; // self executing function here (function() { // your page initialization code here // the DOM will be available here })(); {amp}lt;/script{amp}gt; {amp}lt;/body{amp}gt; {amp}lt;/html{amp}gt; 

Для современных браузеров (от IE9 и новее и любой версии Chrome, Firefox или Safari), если вы хотите иметь возможность реализовать метод jQuery, такой как $(document).ready() , который можно вызывать из любого места (не беспокоясь о где расположен вызывающий скрипт), вы можете просто использовать что-то вроде этого:

 function docReady(fn) { // see if DOM is already available if (document.readyState === "complete" || document.readyState === "interactive") { // call on next available tick setTimeout(fn, 1); } else { document.addEventListener("DOMContentLoaded", fn); } } 

Использование:

 docReady(function() { // DOM is loaded and ready for manipulation here }); 

Если вам нужна полная кросс-браузерная совместимость (включая старые версии IE) и вы не хотите ждать window.onload , то вам, вероятно, стоит взглянуть на то, как фреймворк, такой как jQuery, реализует свой метод $(document).ready() , Это справедливо в зависимости от возможностей браузера.

Чтобы дать вам небольшое представление о том, что делает jQuery (который будет работать везде, где размещен тег script).

Если поддерживается, он пытается стандарт:

 document.addEventListener('DOMContentLoaded', fn, false); 

с отступлением к:

 window.addEventListener('load', fn, false ) 

или для более старых версий IE, он использует:

 document.attachEvent("onreadystatechange", fn); 

с отступлением к:

 window.attachEvent("onload", fn); 

И есть некоторые обходные пути в пути кода IE, которые я не совсем понимаю, но похоже, что это как-то связано с фреймами.


Вот полная замена .ready() jQuery, написанного в простом javascript:

 (function(funcName, baseObj) { // The public function name defaults to window.docReady // but you can pass in your own object and own function name and those will be used // if you want to put them in a different namespace funcName = funcName || "docReady"; baseObj = baseObj || window; var readyList = []; var readyFired = false; var readyEventHandlersInstalled = false; // call this when the document is ready // this function protects itself against being called more than once function ready() { if (!readyFired) { // this must be set to true before we start calling callbacks readyFired = true; for (var i = 0; i {amp}lt; readyList.length; i  ) { // if a callback here happens to add new ready handlers, // the docReady() function will see that it already fired // and will schedule the callback to run right after // this event loop finishes so all handlers will still execute // in order and no new ones will be added to the readyList // while we are processing the list readyList[i].fn.call(window, readyList[i].ctx); } // allow any closures held by these functions to free readyList = []; } } function readyStateChange() { if ( document.readyState === "complete" ) { ready(); } } // This is the one public interface // docReady(fn, context); // the context argument is optional - if present, it will be passed // as an argument to the callback baseObj[funcName] = function(callback, context) { if (typeof callback !== "function") { throw new TypeError("callback for docReady(fn) must be a function"); } // if ready has already fired, then just schedule the callback // to fire asynchronously, but right away if (readyFired) { setTimeout(function() {callback(context);}, 1); return; } else { // add the function and context to the list readyList.push({fn: callback, ctx: context}); } // if document already ready to go, schedule the ready function to run if (document.readyState === "complete") { setTimeout(ready, 1); } else if (!readyEventHandlersInstalled) { // otherwise if we don't have event handlers installed, install them if (document.addEventListener) { // first choice is DOMContentLoaded event document.addEventListener("DOMContentLoaded", ready, false); // backup is window load event window.addEventListener("load", ready, false); } else { // must be IE document.attachEvent("onreadystatechange", readyStateChange); window.attachEvent("onload", ready); } readyEventHandlersInstalled = true; } } })("docReady", window); 

Последняя версия кода общедоступна на GitHub по адресу https://github.com/jfriend00/docReady.

Использование:

 // pass a function reference docReady(fn); // use an anonymous function docReady(function() { // code here }); // pass a function reference and a context // the context will be passed to the function as the first argument docReady(fn, context); // use an anonymous function with a context docReady(function(context) { // code here that can use the context argument that was passed to docReady }, ctx); 

Это было проверено в:

 IE6 and up Firefox 3.6 and up Chrome 14 and up Safari 5.1 and up Opera 11.6 and up Multiple iOS devices Multiple Android devices 

Рабочая реализация и испытательный стенд: http://jsfiddle.net/jfriend00/YfD3C/


Вот краткое изложение того, как это работает:

  1. Создайте IIFE (выражение для немедленного вызова функции), чтобы мы могли иметь непубличные переменные состояния.
  2. docReady(fn, context) публичную функцию docReady(fn, context)
  3. Когда docReady(fn, context) , проверьте, запущен ли уже готовый обработчик. Если это так, просто запланируйте запуск только что добавленного обратного вызова сразу после того, как этот поток JS завершится с setTimeout(fn, 1) .
  4. Если обработчик готовности еще не сработал, добавьте этот новый обратный вызов в список обратных вызовов, которые будут вызваны позже.
  5. Проверьте, готов ли документ. Если это так, выполните все готовые обработчики.
  6. Если мы еще не установили прослушиватели событий, чтобы знать, когда документ будет готов, установите их сейчас.
  7. Если document.addEventListener существует, то установите обработчики событий, используя .addEventListener() для "DOMContentLoaded" и "load" . «Загрузка» является резервным событием для безопасности и не должна быть необходима.
  8. Если document.addEventListener не существует, то установите обработчики событий, используя .attachEvent() для "onreadystatechange" и "onload" .
  9. В событии onreadystatechange проверьте, является ли document.readyState === "complete" и, если это так, вызовите функцию для запуска всех готовых обработчиков.
  10. Во всех других обработчиках событий вызывайте функцию для запуска всех готовых обработчиков.
  11. В функции, чтобы вызвать все готовые обработчики, проверьте переменную состояния, чтобы увидеть, запущены ли мы уже. Если у нас есть, ничего не делать. Если мы еще не были вызваны, то перебираем массив готовых функций и вызываем каждую из них в порядке их добавления. Установите флаг, чтобы указать, что все они были вызваны, чтобы они никогда не выполнялись более одного раза.
  12. Очистите массив функций, чтобы любые замыкания, которые они могли использовать, могли быть освобождены.

Обработчики, зарегистрированные в docReady() , гарантированно будут запущены в том порядке, в котором они были зарегистрированы.

Если вы вызываете docReady(fn) после того, как документ уже готов, обратный вызов будет запланирован на выполнение, как только текущий поток выполнения завершит работу с использованием setTimeout(fn, 1) . Это позволяет вызывающему коду всегда предполагать, что они являются асинхронными обратными вызовами, которые будут вызваны позже, даже если позднее это произойдет, как только текущий поток JS завершит свою работу, и он сохранит порядок вызова.

Понравилась статья? Поделиться с друзьями:
JavaScript & TypeScript
Adblock
detector