Как выполнить динамически загруженный блок JavaScript? - программирование

Как выполнить динамически загруженный блок JavaScript?

Я работаю на веб-странице, где я делаю вызов AJAX, который возвращает кусок HTML, например:

<div>
  <!-- some html -->
  <script type="text/javascript">
    /** some javascript */
  </script>
</div>

Я вставляю все это в DOM, но JavaScript не запускается. Есть ли способ запустить его?

Некоторые подробности: я не могу контролировать, что в блоке script (поэтому я не могу изменить его на функцию, которая может быть вызвана), мне просто нужен весь блок, который будет выполнен. Я не могу назвать eval ответом, потому что JavaScript находится в более крупном блоке HTML. Я мог бы сделать какое-то регулярное выражение, чтобы отделить JavaScript, а затем вызвать eval на нем, но это довольно yucky. Кто-нибудь знает лучший способ?

4b9b3361

Ответ 1

Script, добавленный установкой свойства innerHTML элемента, не выполняется. Попробуйте создать новый div, установив его innerHTML, а затем добавив этот новый div в DOM. Например:

<html>
<head>
<script type='text/javascript'>
function addScript()
{
    var str = "<script>alert('i am here');<\/script>";
    var newdiv = document.createElement('div');
    newdiv.innerHTML = str;
    document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>

Ответ 2

Вам не нужно использовать регулярное выражение, если вы используете ответ для заполнения div или чего-то еще. Вы можете использовать getElementsByTagName.

div.innerHTML = response;
var scripts = div.getElementsByTagName('script');
for (var ix = 0; ix < scripts.length; ix++) {
    eval(scripts[ix].text);
}

Ответ 3

В то время как принятый ответ от @Ed. не работает с текущими версиями браузеров Firefox, браузера Google Chrome или Safari. Мне удалось использовать его пример, чтобы вызывать динамически добавленные скрипты.

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

<html>
<head>
<script type='text/javascript'>
function addScript()
{
    var newdiv = document.createElement('div');

    var p = document.createElement('p');
    p.innerHTML = "Dynamically added text";
    newdiv.appendChild(p);

    var script = document.createElement('script');
    script.innerHTML = "alert('i am here');";
    newdiv.appendChild(script);

    document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>

Это работает для меня в Firefox 42, Google Chrome 48 и Safari 9.0.3

Ответ 4

Альтернативой является не просто сброс возврата из вызова Ajax в DOM с помощью InnerHTML.

Вы можете динамически вставлять каждый node, а затем запускать script.

В противном случае браузер просто предполагает, что вы вставляете текст node и игнорируете скрипты.

Использование Eval является довольно злым, потому что для его запуска требуется другой экземпляр Javascript VM и JIT переданная строка.

Ответ 6

Лучшим методом, вероятно, будет идентификация и анализ содержимого блока script непосредственно через DOM.

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

Все, что вы реализуете, может быть использовано для XSS.

Ответ 7

Вы можете использовать одну из популярных библиотек Ajax, которые делают это для вас изначально. Мне нравится Prototype. Вы можете просто добавить evalScripts: true как часть вашего вызова Ajax, и это происходит автоматически.

Ответ 8

Ниже представлен немного другой подход, который использует тот факт, что если тег содержит type = "text/xml", внутри JavaScript не будет выполняться:

function preventJS(html) {
    return html.replace(/<script(?=(\s|>))/i, '<script type="text/xml" ');
}

Вы можете прочитать больше здесь - JavaScript: как предотвратить выполнение JavaScript внутри html, добавляемого в DOM. Если это сработает для вас, пожалуйста, оставьте здесь комментарий с информацией о том, какой браузер и версия вы использовали.