QA Fest — конференция №1 по тестированию и автоматизации. Финальная программа уже на сайте >>
×Закрыть

AJAX-проблемы

Сегодня с моим напарником Никитой разбирались, как динамически подгружать инфу на страницу без использования ифрейма. «Конечно, AJAX! » — привычно скажут продвинутые девелоперы и стройными рядами уйдут курить кеды. Фикус в том, что если в динамически подгруженный и отображённый на странице хтмл случайно затешется скрипт на яваскрипте, то он не выполнится. Просто отобразится хтмл и всё. Пример для неверующих:

<div id="output"></div> <script> var name = 'output'; var the_div = document.getElementById(name); if(null!=the_div) the_div.innerHTML = '<em>some HTML with JavaScripts here <script>alert(666)<\/script> another one <script href="<a href=" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" class="linkification-ext" href="<a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>"><\/script>'; else alert('cannot find the <div>'); </div></script></script></em></script>

То бишь есть див, в который подгружается некий хтмл (динамику этой загрузки пока оставим в стороне). Выполнится имеющийся в этом куске хтмля яваскрипт? Фиг.

Что делать? Стали копать исходники, как-то ж люди это делают. Пошли на уважаемый мной сайт dklab.ru и стали рыть пример имеющегося там движка типа AJAX’a. Что выяснили:

  1. создаётся контейнер (див или спан);
  2. в него помещается хтмл с одним яваскриптом, причём перед тегом <script> должен быть какой-то текст, а то у ИЕ с этим проблемы;
  3. далее берётся первый элемент массива скриптов этого контейнера (об этом ниже);
  4. обновляется его сурс (свойство «src»), что является отмашкой для запуска этого кода.
Общий вывод: хочешь запустить такой яваскрипт — обнови его сурс.

Посему поэтому приведённый выше код должен быть исправлен так:

<div id="output"></div> <script> var name = 'output'; var the_div = document.getElementById(name); if(null!=the_div) { the_div.innerHTML = '<em>some HTML with JavaScripts here <script>alert(666)<\/script> another one <script href="<a href=" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" class="linkification-ext" href="<a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>" target="_blank"><a href="<a href=" target="_blank">ya.ru</a>" target="_blank"><a href="http://ya.ru" target="_blank">ya.ru</a>"><\/script>'; <strong>run_js(name);</strong> } else alert('cannot find the <div>'); </div></script></script></em></script>

обращаем внимание на выделенный кусок «run_js (name) ». Это специальная функция, которая пробегает по массиву всех имеющихся в указанном контейнере скриптов, благо такая функциональность предоставляется броузером, и обновляем его сурс. Но тут одна загвоздка: если указать тегу script сурс, то автоматически перестаёт работать содержимое тега, просто не запускается. Например:

<script href="http://someserver.ua/1.js" target="_blank"><a href="http://someserver.ua/1.js" target="_blank">someserver.ua/1.js</a>" class="linkification-ext" href="<a href="<a href=" target="_blank">someserver.ua/1.js</a>" target="_blank"><a href="http://someserver.ua/1.js" target="_blank">someserver.ua/1.js</a>"><a href="<a href=" target="_blank">someserver.ua/1.js</a>" target="_blank"><a href="http://someserver.ua/1.js" target="_blank">someserver.ua/1.js</a>"> alert(4444); </script>

Это как в правилах дорожного движения — если есть светофор, то знаки приоритета теряют силу. Таким образом, алерт не запустится, а выполнится только указанный файл.

Теперь вернёмся к проблеме: как обновить сурс так, чтобы:
случай А) если его нет, то он и не появился,
случай Б) если он есть, то изменился так, чтобы указывал на тот же самый файл.

Ответ:
случай А) обновить пустой строкой,
случай Б) приписать ничего не значащий УРЛ-параметр, например, «?1=2» или «&1=2» в зависимости от наличия других параметров.

Так или иначе, вот код многострадальной функции для запуска *статичного* JavaScript:

<script> function run_js(name) { var the_div = document.getElementById(name); if(null!=the_div) { with(the_div) { var arr_scripts = the_div.getElementsByTagName("script"); for(i in arr_scripts) { var src = arr_scripts[i].src; if(null!=src) { var has_question = (src.indexOf('?', 1)>0 ? true : false ); if(0==src.length) arr_scripts[i].setAttribute('src', ''); else arr_scripts[i].setAttribute('src', arr_scripts[i].src + (has_question==true ? '&' : '?') + '1=1'); } } } } } </script>

LinkedIn

15 комментариев

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.

Метод Zeke не работает в IE 6


alert#div1{HEIGHT: 100;WIDTH: 100;BACKGROUND-COLOR: #dfe6ef;BORDER: #aca794 1px solid}#span1{HEIGHT: 50;WIDTH: 50;BACKGROUND-COLOR: red;BORDER: blue 1px solid}var param;param="1alert(’Im in Run’);";function run(p){var NewDiv = document.createElement("DIV");var OldDiv = document.getElementById("div1");var OldParent = OldDiv.parentNode;// Нак нельзя//NewDiv.innerHTML = p;// Только такNewDiv.innerHTML = ’’+p+’’;OldParent.replaceChild(NewDiv, OldDiv);// тоже, но одной строкой//document.getElementById("div1").innerHTML = p;}Old TEXT element DIValert(’param’)Replace DIV

Работает в Mozilla/5.0 — Firefox/3.0Но не работает в IEalert#div1 {HEIGHT: 100; WIDTH: 100; BACKGROUND-COLOR: #dfe6ef; BORDER: #aca794 1 px solid} #span1 {HEIGHT: 50; WIDTH: 50; BACKGROUND-COLOR: red; BORDER: blue 1 px solid} var param; param="1alert (’Im in Run’); “; function run (p) {var NewDiv = document.createElement ( “DIV” ); var OldDiv = document.getElementById ( “div1” ); var OldParent = OldDiv.parentNode; // Нак нельзя//NewDiv.innerHTML = p; // Только такNewDiv.innerHTML = ’’+p+’’; OldParent.replaceChild (NewDiv, OldDiv); // тоже, но одной строкой//document.getElementById ( “div1” ).innerHTML = p; } Old TEXT element DIValert (’param’) Replace DIV

2 ZekeПрошу объяснить подробнее. Заранее спасибо.

Ребята, «курите» www.fullajax.ru — много проблем решено на автоматическом уровне... — Корректная работа под основными браузерами (Internet Explorer, Firefox, Opera, Safari) — Прямые ссылки на AJAX сгенерированные вебстраницы — История для кнопок в браузере «Назад» и «Вперед» — Корректная работа счетчиков — Обновление баннеров с каждым обновлением информации — Функция изменение TITLE — Мультипоточность — Полная поддержка GET и POST запросов — Раздельная история для каждого потока загрузки веб-страниц — Парсинг и выполнение скриптов, линков и стилей в контенте динамически подгружаемых веб-страниц — Реализация связанного меню — Используется различные уровни кеширования как HTML, так и скриптов. — Возможность отключения переинициализации сриптовых функций (отключение повторного исполнения) — повышает производительность, экономит вычислительные ресурсы и оперативную память. Возможна тонкая натройка. — Загрузка на сервер (upload) файлов без перезагрузки — Авто-фильтр — ссылки по указанным критериям автоматически превращаются в AJAX — Триггер контента — Ускоритель загрузки скриптов — паралельная загрузка с последовательным примнением — Препроцессорная обработка ответов сервера — Корректная обработка document.write в динамически подгружаемых страницах — Поддержка событий onload и onunload тега для каждого потока — Поддержка отработки на локальной файловой системе

Решил мою проблему, благодарствую:)

Метод Zeke не работает в Opera 9.10...

способ, предложенный Zeke отлично работает.

2ZekeИнтересный подход, надо будет попробовать.

Используйте DOM, не будет таких проблем. Сначала — createElement, потом ему запихать текст в innerHTML и сделать replaceChild для родителя. Работает во всех бравзерах.

XSLT, тебе поможет, ведь, все есть, а вручную трансформировать то зачем? (я тож когдато мучился, только не из javascript, а из style)

Возвращать JavaScript в responseText — это изврат

А почему нет? Получается, что парикмахерам нельзя стричься:] Кроме того, я не всегда знаю, какого вида придёт хтмл — с яваскриптом либо без оного. Поделись, если знаешь другой подход акромя описанного да использования ифрейма.

Ошибка в самом подходе.Возвращать JavaScript в responseText — это изврат.

Для таво, чтобы не приходилось курить кеды, нужно курить документацию:) В харячо любимом усеми нами ИнтернетЭксплорере естьспециальный атрибут тега. DEFFER называется (за количество букв F не отвечаю). Так вот, если ейный указан, скриптысами (шайтан!) выполняются при загрузке.Если же наш суперсайт ориентирован еще и на вражеские firefox и safari к примеру (для экзотики), то придется покурить вот это. У вот этого есть замечательный параметр в одной из хвункций, зовется evalScripts. Или runScripts...Но честно говоря, я тоже в отдельных случаях не избежал описанного в посте способа: (Потомушто AJAX.

Подписаться на комментарии