Как выполнить динамически загруженный блок JavaScript?
Я работаю на веб-странице, где я делаю вызов AJAX, который возвращает кусок HTML, например:
<div>
<!-- some html -->
<script type="text/javascript">
/** some javascript */
</script>
</div>
Я вставляю все это в DOM, но JavaScript не запускается. Есть ли способ запустить его?
Некоторые подробности: я не могу контролировать, что в блоке script (поэтому я не могу изменить его на функцию, которая может быть вызвана), мне просто нужен весь блок, который будет выполнен. Я не могу назвать eval ответом, потому что JavaScript находится в более крупном блоке HTML. Я мог бы сделать какое-то регулярное выражение, чтобы отделить JavaScript, а затем вызвать eval на нем, но это довольно yucky. Кто-нибудь знает лучший способ?
Ответы
Ответ 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 переданная строка.
Ответ 5
У меня нет решения, но вы можете найти то, что вы ищете здесь:
http://ajaxpatterns.org/On-Demand_Javascript
Ответ 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.
Если это сработает для вас, пожалуйста, оставьте здесь комментарий с информацией о том, какой браузер и версия вы использовали.