Триггер $document.ready (поэтому код AJAX, который я не могу изменить, выполняется)

Мои требования следующие:

  • У меня есть богатая веб-страница, которая в определенный момент загружает кучу HTML в div через AJAX.
  • HTML, который я получаю, содержит javascript (<script>...</script>)
  • Полученный javascript содержит $('document').ready( ... ) частей
  • Я не могу изменить полученный javascript; это происходит из внешней библиотеки
  • У меня есть функция javascript, которая вызывается при загрузке AJAX. Я пытаюсь «обмануть» его выполнение, выполнив:

    function AjaxLoaded() {
      $('document').trigger('ready');
    }
    

Боюсь, это не поможет.

Я видел несколько ответы на переполнение стека, которые "уклоняются" от этого вопроса, изменяя код, который возвращается на AJAX (сделайте его функцию и вызовите ее после загрузки или просто удалите $(document).ready()). Я должен подчеркнуть, что в этом случае я не могу изменить полученный код.


person kikito    schedule 10.02.2010    source источник
comment
это была интересная проблема, мне пришлось посмотреть код jquery, чтобы увидеть, что происходит с готовыми событиями.   -  person John Boker    schedule 10.02.2010


Ответы (6)


После некоторых исследований я создал способ заставить его работать.

вот мой тест, который показывает, что он работает: http://www.antiyes.com/test/test2.php

вот соответствующий код:

<script>
    // easy copy of an array
    Array.prototype.copy = function() {
        return [].concat(this);
    };

    // this function is added to jQuery, it allows access to the readylist
    // it works for jQuery 1.3.2, it might break on future versions
    $.getReadyList = function() {
        if(this.readyList != null)
            this.myreadylist =  this.readyList.copy();      
        return this.myreadylist;
    };

    $(document).ready(function() {
        alert("blah");
    });

</script>

<script>

    // this should be added last so it gets all the ready event
    $(document).ready(function() {
        readylist = $.getReadyList();
    });

</script>

то в теле у меня есть:

<input type="button" onclick="$(readylist).each(function(){this();});" value="trigger ready" />

в основном, что я сделал, это добавил функцию в jQuery, которая копирует readyList до того, как он будет очищен, после чего он будет доступен для использования вами.

похоже, приведенный ниже код не работает:

function AjaxLoaded() {
    $(document).trigger('ready');
}

опустите кавычки вокруг document.

person John Boker    schedule 10.02.2010
comment
Имеет смысл, поскольку документ является объектом, а не элементом. +1 за исследования. - person Mark Schultheiss; 10.02.2010
comment
Джон, ты полностью взорвал мой мозг этим. Это определенно +1 и правильный ответ! Всего один небольшой комментарий: не могли бы вы включить код в ответ в дополнение к ссылке на тестовую страницу? Это слишком хорошо, чтобы потеряться, если через два года сменить хостинг :) - person kikito; 10.02.2010
comment
Отличная работа над этим обходным путем; очень полезно. Кроме того, очень хорошая работа по объяснению и предоставлению рабочей демонстрации. Спасибо. - person Jessy Houle; 01.06.2010
comment
Просто предупреждение, я не могу заставить это работать с jQuery 1.4.4. - person James Nail; 17.12.2010
comment
Как упоминает @JamesNail, к сожалению, это отличное решение не работает с jQuery 1.4 и более поздними версиями. Это связано с тем, что список readyList больше не отображается, как обсуждалось здесь. Я опубликую восстановленное решение ниже. - person rakaloof; 14.11.2011

Поскольку готовый список jQuery не отображается в версии 1.4 (обсуждается здесь) приведенные выше хорошие решения не работают.

Обойти это можно, создав собственный список готовых с помощью переопределения исходного метода jQuery-ready. Это необходимо сделать до того, как будут загружены другие скрипты, использующие исходный готовый метод. В остальном тот же код, что и для John/Kikito:

// Overrides jQuery-ready and makes it triggerable with $.triggerReady
// This script needs to be included before other scripts using the jQuery-ready.
// Tested with jQuery 1.7
(function(){
var readyList = [];

// Store a reference to the original ready method.
var originalReadyMethod = jQuery.fn.ready;

// Override jQuery.fn.ready
jQuery.fn.ready = function(){
if(arguments.length && arguments.length > 0 && typeof arguments[0] === 'function') {
  readyList.push(arguments[0]);
}

// Execute the original method.
originalReadyMethod.apply( this, arguments );
};

// Used to trigger all ready events
$.triggerReady = function() {
  $(readyList).each(function(){this();});
};
})();

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

person rakaloof    schedule 14.11.2011
comment
Имейте в виду, что это $(readyList).each(function(){this();});, заглавная L - person digital illusion; 30.11.2011
comment
+1, это решение все еще работает с 1.10.1. Я сделал скрипку и использовал ее в ответ, явно ссылаясь на это как на источник. Отличная работа @rakaloof - person Andrea Ligios; 24.01.2014

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

// jquery_trigger_ready.js
// this function is added to jQuery, it allows access to the readylist
// it works for jQuery 1.3.2, it might break on future versions
$.getReadyList = function() {
  if(this.readyList != null) { this.myreadylist = [].concat(this.readyList); }
  return this.myreadylist;
};

$(document).ready(function() {
  readylist = $.getReadyList();
});

$.triggerReady = function() {
  $(readylist).each(function(){this();});
}

Включение этого файла после включения jquery позволяет выполнить запуск, вызвав $.triggerReady(). Пример:

<html>
  <head>
    <title>trigger ready event</title>
    <script src="test2_files/jquery-1.js" type="text/javascript"></script>
    <script src="jquery_trigger_ready.js" type="text/javascript"></script>
  </head>
  <body>
    <input onclick="$.triggerReady();" value="trigger ready" type="button">
    <script type="text/javascript">
      $(document).ready(function(){
          alert("blah");
      });
    </script>
  </body>
</html>

Кстати, я хотел сделать его $(document).triggerReady(). Если кто-то готов поделиться некоторыми советами по этому поводу, буду признателен.

person kikito    schedule 14.02.2010
comment
вы имеете в виду $(document).__proto__.triggerReady = function() { $(readylist).each(function(){this();}); } ? Я знаю, что proto устарел, но это единственное, что работает в Opera... - person SparK; 20.10.2011
comment
Извините, я понятия не имею, о чем вы говорите. Opera не добавляет функции в $? - person kikito; 21.10.2011
comment
есть и другой способ использования прототипов, но Opera поддерживает только старый способ — proto. кстати, эта строка в моем другом комментарии: вместо использования $.triggerReady вы используете $(document).__proto__.triggerReady, чтобы вы могли использовать $(document).triggerReady(); как ты хотел. - person SparK; 24.10.2011
comment
Это странно. Opera обычно очень хороша в стандартах и ​​прочем. У вас есть ссылка на документ или пример, который показывает это? Я ничего не нашел. - person kikito; 24.10.2011
comment
getPrototypeOf в MDN здесь, это обычный способ, но тогда в конце страницы говорится, что Opera не может с этим справиться, даже несмотря на то, что это ссылка Mozilla, я думаю, ей можно доверять ... - person SparK; 24.10.2011
comment
Я немного исследовал это. У меня нет Оперы, поэтому проверить не могу - но вроде последняя Опера поддерживает. Чтобы быть уверенным, есть способ предоставить getPrototypeOf во всех навигаторах, у которых его нет здесь: ejohn.org/ blog/objectgetprototypeof Я предлагаю вам использовать его, если вам нужен getPrototypeOf. С Уважением! - person kikito; 24.10.2011

У нас была такая же проблема, но мы решили ее другим способом.

Вместо

$(document).ready(function () {
  $('.specialClass').click(....

Мы использовали :

$(document).bind('ready', function(event) {
  $('.specialClass', event.target).click(..

jQuery, как обычно, инициирует событие «готово» для документа. Когда мы загружаем содержимое нового div через ajax, мы можем написать:

loadedDiv.trigger('ready')

И вся инициализация выполняется только в div, получая то, что ожидалось.

person Simone Gianni    schedule 14.07.2010
comment
Мне очень нравится это решение, но с тех пор, как оно было опубликовано, оно было добавлено в документы jQuery: $(document).bind(ready, handler), устарело с jQuery 1.8 Я пытался переключиться на on(), и это почти работает, за исключением того, что document ready не вызывает его. Может быть из-за устаревания или из-за этой части документа: если событие готовности уже запущено, и вы пытаетесь выполнить .bind(ready), связанный обработчик не будет выполнен. Любые мысли о том, как сделать это решение Работа? - person John-Philip; 30.11.2012

Ответ Симоны Джанни я считаю самым элегантным и чистым.

и вы даже можете упростить его, чтобы он стал еще более простым в использовании:

jQuery.fn.loadExtended = function(url,completeCallback){
    return this.load(url,function(responseText, textStatus, XMLHttpRequest) {
        if (completeCallback !== undefined && completeCallback !== null) {
            completeCallback(responseText, textStatus, XMLHttpRequest);
        }
        $(this).trigger("ready");
    });
};

Итак, теперь вместо использования:

$(".container").load(url,function(responseText, textStatus, XMLHttpRequest) {
    $(this).trigger("ready");
});

вы можете просто использовать:

$(".container").loadExtended("tag_cloud.html");

or:

$(".container").loadExtended("tag_cloud.html",function(){ 
    alert('callback function') 
});

Это имеет то преимущество, что триггер применяется только к обновляемому div.

person Uoli    schedule 08.09.2010

Если ваш новый загруженный HTML содержит <script> элементов, и вы пытаетесь вставить его в основной HTML с помощью чистого JS (element.innerHTML = newHTML), то $(document).ready обработчики в newHTML и обернутые функции, такие как (function() { /* some functions */ })();, не будут выполняться, потому что JQuery отвязывает 'ready' событие после первого запуска, и вы не можете запускать его повторно PS. Но вы можете использовать $.holdReady(true) и запускать, когда это необходимо.

Итак, попробуйте вставить код методом jquery, $(element).html(newHTML). Это решило аналогичную проблему для меня, кажется, jquery обрабатывает js перед вставкой. Используя этот метод, вы также не увидите элементы <script> среди узлов DOM (например, в инспекторе элементов браузера).

person linkuha    schedule 21.08.2019