Использование .ready() перед включением jQuery
В этой заметке предлагается метод, который позволяет использовать метод jQuery.ready()
в любом месте документа, даже если сам jQuery подключается в самом низу.
Идея в том, чтобы переместить JavaScript код в конец HTML-документа, используя для этого сам JavaScript. Идея была взята от сюда Stop paying your jQuery tax.
Метод заключается в следующем:
-
В
head
включается сценарий, который:- Создает массив.
- Создает поддельную функцию $, которая перемещает аргументы вызова в этот массив.
- В
body
, после включения jQuery, ставим скрипт, который:- Использует jQuery для перебора содержимого нашего массива.
- ...и вызывает настоящую функцию $, передавая сохраненные аргументы (функции).
Реализация для WordPress
Для WordPress эта идея реализовывается таким PHP кодом в файле functions.php:
// Ability to use jQuery.ready() before jQuery is enabled // 0 priority is important in some cases add_action( 'wp_head', 'jquery_ready_catch', 1 ); function safe_jquery_ready(){ add_action( 'wp_footer', __FUNCTION__, PHP_INT_MAX ); echo '<script>' . ( doing_action( 'wp_head' ) ? '(function(w,d,u){w.readyQ=[];w.bindReadyQ=[];function p(x,y){if(x=="ready"){w.bindReadyQ.push(y);}'. 'else{w.readyQ.push(x);}};var a={ready:p,bind:p};w.$=w.jQuery=function(f){if(f===d||f===u){return a}'. 'else{p(f)}}})(window,document)' : '(function($,d){$.each(readyQ,function(i,f){$(f)});$.each(bindReadyQ,function(i,f){$(d).bind("ready",f)})})(jQuery,document)' ) . "</script>\n"; }
Пояснения
Рассмотрим минифицированный JS код выше в нормальном виде:
(function (w, d, u) { // Define two queues for handlers w.readyQ = []; w.bindReadyQ = []; // Push a handler into the correct queue function pushToQ(x, y) { if (x == "ready") { w.bindReadyQ.push(y); } else { w.readyQ.push(x); } } // Define an alias object (for use later) var alias = { ready: pushToQ, bind: pushToQ } // Define the fake jQuery function to capture handlers w.$ = w.jQuery = function (handler) { if (handler === d || handler === u) { // Queue $(document).ready(handler), $().ready(handler) // and $(document).bind("ready", handler) by returning // an object with alias methods for pushToQ return alias; } else { // Queue $(handler) pushToQ(handler); } } })(window, document);
Если вы посмотрите документацию по методу jQuery.ready(), там объясняется, что если обработчики привязаны к DOM ready с помощью функции .bind()
, то на самом деле они срабатывают после срабатывания всех других обработчиков. Именно поэтому у нас есть две очереди - для того, чтобы соблюсти это поведение.
Развернув сценарий body (сразу после jQuery), мы получаем:
(function ($, doc) { $.each(readyQ, function (index, handler) { $(handler); }); $.each(bindReadyQ, function (index, handler) { $(doc).bind("ready", handler); }); })(jQuery, document);
Точно так же, как в примере Сэма, мы используем метод jQuery.each()
, чтобы правильно связать все наши обработчики очереди с DOM ready, но поскольку $(document).bind("ready", handler)
мог быть вызван раньше, мы свяжем их тоже правильным образом.
Пример
<!DOCTYPE html> <html> <head> <title>Example</title> <script> (function(w,d,u){w.readyQ=[];w.bindReadyQ=[]; function p(x,y){if(x=="ready"){w.bindReadyQ.push(y);}else{w.readyQ.push(x);}}; var a={ready:p,bind:p};w.$=w.jQuery=function(f){if(f===d||f===u){ return a}else{p(f)}}} )(window,document) </script> </head> <body> <script> $(document).bind("ready", function () { console.log("Example D: $(document).bind(\"ready\", handler)"); }); $(document).ready(function () { console.log("Example A: $(document).ready(handler)"); }); $().ready(function () { console.log("Example B: $().ready(handler)"); }); $(function(){ console.log("Example C: $(handler)"); }); </script> <!-- HTML КОД СТРАНИЦЫ --> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> <script> (function($,d){$.each(readyQ,function(i,f){$(f)}); $.each(bindReadyQ,function(i,f){$(d).bind("ready",f)})})(jQuery,document) </script> </body> </html>
Вывод:
Example A: $(document).ready(handler) Example B: $().ready(handler) Example C: $(handler) Example D: $(document).bind("ready", handler)
Обратите внимание, что хотя Example D первый, в нем используется $(document).bind("ready", handler)
, поэтому он ставится в очередь и выполняется после трех других примеров. Он ведет себя именно так, как задумано jQuery.
--