Виконання <script> вводиться innerHTML після виклику AJAX


100

Є розділ під назвою "Вміст":

<div id="content"></div>

Він повинен бути заповнений AJAX даними з файлу PHP, включаючи <script>тег. Однак сценарій всередині цього тегу не виконується.

<div id="content"><!-- After AJAX loads the stuff that goes here -->
   <script type="text/javascript">
     //code
   </script>
   <!-- More stuff that DOES work here -->
</div>

Як ви завантажуєте діва? Залежно від бібліотеки, яку ви використовуєте, ви можете нормально контролювати, чи просто ви хочете виконати сценарії після завантаження ajax.
Білл Ян

1
Після window.onloadстворення XMTHttpRequestоб’єкта я запитую іншу сторінку (php), яка містить вміст div, включаючи сценарій. Я роблю це з простого JS, без бібліотек (крім моєї власної лол)
JCOC611,

Відповіді:


65

JavaScript, вставлений як текст DOM, не виконується. Однак ви можете використовувати динамічний шаблон сценарію для досягнення своєї мети. Основна ідея - перемістити сценарій, який ви хочете виконати, у зовнішній файл та створити тег сценарію, коли отримаєте відповідь на Ajax. Потім ви встановлюєте srcатрибут тегу сценарію та вуаля, він завантажує та виконує зовнішній скрипт.

Ця інша публікація StackOverflow також може бути корисною для вас: Чи можна вставляти скрипти з InternalHTML? .


Ви можете вибрати всі завантажені сценарії та виконати їх за допомогою функції eval ():$('#audit-view script').each(function (index, element) { eval(element.innerHTML); })
Jerzy Gebler,

Javascript, доданий на сторінку, повинен абсолютно виконати. (наприклад, jsfiddle.net/wnn5fz3m/1 ). Питання в тому, чому це не іноді?
NoBugs

@Chocula я перемістив свій скрипт в окремий файл, але він не працює з часткового, чи можете ви допомогти з цим? stackoverflow.com/questions/42941856/…
Самра

FYI (@NoBugs дає мені підказку). Я спробував звичайний javascirpt element.innerHTML = zzz та desnt робота. Потім я спробував Jquery $ (element) .html (zzz) і працював.
gtryonp

66

Я використав цей код, він працює чудово

var arr = MyDiv.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
    eval(arr[n].innerHTML)//run script inside div

4
Якщо ви запитаєте мене, це набагато краща відповідь, ніж прийнята. Це майже ін'єкція JavaScript.
Xedret

Хоча це корисно, це дійсно не відповідає на питання, чому сценарії не запускаються. Дивіться, наприклад, jsfiddle.net/fkqmcaz7 та jsfiddle.net/wnn5fz3m/1 Він абсолютно повинен працювати, і я не знаходжу спрощеного випадку, коли він не працює.
NoBugs

1
@NaoiseGolden OP буквально запитує про виконання сценарію, тому я думаю, що це нормально. :-)
thedayturns

1
Не рекомендується Eval (). Дивіться це - stackoverflow.com/questions/9107847/…
Королі

15

Якщо ви завантажите скрипт-блок у своєму діві через Ajax так:

<div id="content">
    <script type="text/javascript">
    function myFunction() {
      //do something
    }
    myFunction();
    </script>
</div>

... він просто оновлює DOM вашої сторінки, myFunction () не обов'язково викликається.

Ви можете використовувати метод зворотного виклику Ajax, такий як метод в ajax () jQuery, щоб визначити, що потрібно виконати, коли запит закінчується.

Те, що ви робите, відрізняється від завантаження сторінки з включеним у неї JavaScript від get-go (що і виконується).

Приклад, як використовувати зворотний виклик успіху та помилки після отримання певного вмісту:

  $.ajax({
    type: 'GET',
    url: 'response.php',
    timeout: 2000,
    success: function(data) {
      $("#content").html(data);
      myFunction();
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) {
      alert("error retrieving content");
    }

Інший швидкий і брудний спосіб - використовувати eval () для виконання будь-якого коду сценарію, який ви вставили як текст DOM, якщо ви не хочете використовувати jQuery або іншу бібліотеку.


використовуючи зворотний дзвінок jQuery, як я можу "виконати" код всередині нового <script>?
JCOC611

Я додав приклад використання зворотного виклику успіху:
Крістофер Токар

1
Дуже дякую! the "myFunction ();" частина полягала в тому, що я залишав поза кодом.
Джейсон

11

Ось сценарій, який буде оцінювати всі теги сценарію в тексті.

function evalJSFromHtml(html) {
  var newElement = document.createElement('div');
  newElement.innerHTML = html;

  var scripts = newElement.getElementsByTagName("script");
  for (var i = 0; i < scripts.length; ++i) {
    var script = scripts[i];
    eval(script.innerHTML);
  }
}

Просто зателефонуйте до цієї функції після отримання HTML-сервера від сервера. Будьте попереджені: використання evalможе бути небезпечним.

Демо: http://plnkr.co/edit/LA7OPkRfAtgOhwcAnLrl?p=preview


5

Це "просто працює" для мене, використовуючи jQuery, за умови, що ви не намагаєтесь додати до документа підмножину поверненого XHR HTML. (Дивіться цей звіт про помилку, який показує проблему з jQuery.)

Ось приклад, що показує його роботу:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
<html lang="en"> 
<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
    <title>test_1.4</title> 
    <script type="text/javascript" charset="utf-8" src="jquery.1.4.2.js"></script> 
    <script type="text/javascript" charset="utf-8"> 
        var snippet = "<div><span id='a'>JS did not run<\/span><script type='text/javascript'>" +
        "$('#a').html('Hooray! JS ran!');" +
        "<\/script><\/div>";
        $(function(){
            $('#replaceable').replaceWith($(snippet));
        });
    </script> 
</head> 
<body> 
    <div id="replaceable">I'm going away.</div> 
</body> 
</html>

Ось еквівалент вищезазначеного: http://jsfiddle.net/2CTLH/


1
Навряд чи це було б вирішенням проблеми в даний час, оскільки це була помилка з дійсно старою версією jQuery.
NoBugs

3

Ось функція, яку ви можете використовувати для розбору відповідей AJAX, особливо якщо ви використовуєте minifiedjs і хочете, щоб він виконував повернений Javascript або просто хотів проаналізувати сценарії, не додаючи їх до DOM, він також обробляє помилки виключень. Я використовував цей код у бібліотеці php4sack, і він корисний поза бібліотекою.

function parseScript(_source) {
    var source = _source;
    var scripts = new Array();

    // Strip out tags
    while(source.toLowerCase().indexOf("<script") > -1 || source.toLowerCase().indexOf("</script") > -1) {
        var s = source.toLowerCase().indexOf("<script");
        var s_e = source.indexOf(">", s);
        var e = source.toLowerCase().indexOf("</script", s);
        var e_e = source.indexOf(">", e);

        // Add to scripts array
        scripts.push(source.substring(s_e+1, e));
        // Strip from source
        source = source.substring(0, s) + source.substring(e_e+1);
    }

    // Loop through every script collected and eval it
    for(var i=0; i<scripts.length; i++) {
        try {
          if (scripts[i] != '')
          {         
            try  {          //IE
                  execScript(scripts[i]);   
      }
      catch(ex)           //Firefox
      {
        window.eval(scripts[i]);
      }   

            }  
        }
        catch(e) {
            // do what you want here when a script fails
         // window.alert('Script failed to run - '+scripts[i]);
          if (e instanceof SyntaxError) console.log (e.message+' - '+scripts[i]);
                    }
    }
// Return the cleaned source
    return source;
 }

2

Якщо ви вводите щось, що потребує тегу сценарію, ви можете отримати помилку синтаксису, що не знайдено, і сказати незаконний маркер . Щоб уникнути цього, не забудьте уникнути косої риски в тегах закритого сценарію. тобто;

var output += '<\/script>';

Те саме стосується будь-яких закриваючих тегів, таких як тег форми.


0

Тут у мене було подібне повідомлення, завантаження addEventListener на завантаження ajax БЕЗ jquery

Як я вирішив це, було вставити виклики до функцій в межах моєї функції stateChange. Сторінка, яку я налаштувала, складала 3 кнопки, які завантажували б у contentArea 3 різні сторінки. Оскільки я повинен був знати, яку кнопку натискати для завантаження сторінки 1, 2 або 3, я міг легко використовувати оператори if / else, щоб визначити, яку сторінку завантажують, а потім яку функцію запускати. Що я намагався зробити, це зареєструвати різні слухачі кнопок, які працюватимуть лише при завантаженні певної сторінки через ідентифікатори елементів.

так...

якщо (page1 завантажується, pageload = 1) запустіть функцію registerListeners1

то те саме для сторінки 2 або 3.


0

Це спрацювало для мене, зателефонувавши eval на кожен вміст сценарію з ajax .done:

$.ajax({}).done(function (data) {      
    $('div#content script').each(function (index, element) { eval(element.innerHTML); 
})  

Примітка: я не записав параметри в $ .ajax, які ви повинні налаштувати відповідно до свого ajax.


0

Мій висновок: HTML не дозволяє теги NESTED SCRIPT. Якщо ви використовуєте javascript для введення HTML-коду, який містить теги скриптів всередині, він не працюватиме, тому що javascript також входить у тег сценарію. Ви можете протестувати його з наступним кодом, і ви виявите, що це не буде працювати. Випадок використання - ви викликаєте послугу з AJAX або подібною, ви отримуєте HTML і хочете ввести його в HTML DOM прямо вперед. Якщо введений HTML-код знаходиться всередині SCRIPT, теги не працюватимуть.

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body></body><script>document.getElementsByTagName("body")[0].innerHTML = "<script>console.log('hi there')</script>\n<div>hello world</div>\n"</script></html>

-3

Інша річ, що потрібно зробити, це завантажити сторінку таким сценарієм, як:

<div id="content" onmouseover='myFunction();$(this).prop( 'onmouseover', null );'>
<script type="text/javascript">
function myFunction() {
  //do something
}
myFunction();
</script>
</div>

Це завантажить сторінку, потім запустіть скрипт та видаліть обробник подій, коли функція запущена. Це не запуститься відразу після завантаження ajax, але якщо ви будете чекати, коли користувач введе елемент div, це буде добре.

PS. Потрібен Jquery

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.