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



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вам не нужно использовать регулярное выражение, если вы используете ответ для заполнения div или чего-то еще. Вы можете использовать getElementsByTagName.
div.innerHTML = response;
var scripts = div.getElementsByTagName('script');
for (var ix = 0; ix < scripts.length; ix++) {
eval(scripts[ix].text);
}
Лучшим методом, вероятно, было бы идентифицировать и оценивать содержимое блока скрипта напрямую через DOM.
Я был бы осторожен ... если вы реализуете это, чтобы преодолеть ограничение на некоторые внешние вызовы, вы открываете дыру в безопасности.
Все, что вы реализуете, может быть использовано для XSS.
Поправьте меня, если я ошибаюсь, но, как я понимаю уязвимости XSS в подобных ситуациях, это проблема только в том случае, если вы беспокоитесь о том, что кто-то сможет получить доступ к чужой онлайн-учетной записи и, таким образом, украсть конфиденциальную информацию. info, но если пользователи не могут войти на сайт, не беспокойтесь.
Альтернативой является не просто сбрасывать возврат от вызова Ajax в DOM с помощью InnerHTML.
Вы можете вставлять каждый узел динамически, и тогда скрипт запустится.
В противном случае браузер просто предполагает, что вы вставляете текстовый узел, и игнорирует сценарии.
Использование Eval является довольно злом, потому что требует, чтобы другой экземпляр виртуальной машины Javascript был запущен и JIT переданной строки.
Было бы очень хорошо, если бы вы объяснили, как динамически вставлять каждый узел.
Скрипт, добавленный путем установки свойства 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>
Этот сценарий не работает в IE 7. Похоже, в IE 7 есть ошибка с функцией appendChild.
Вы можете использовать одну из популярных библиотек Ajax, которая делает это за вас изначально. Мне нравится Прототип. Вы можете просто добавить evalScripts: true как часть вашего вызова Ajax, и это произойдет автоматически.
Хотя принятый ответ от @Ed. не работает в текущих версиях браузеров Firefox, Google Chrome или Safari. Мне удалось освоить его пример, чтобы вызывать динамически добавленные скрипты.
Необходимые изменения касаются только способа добавления скриптов в DOM. Вместо того, чтобы добавлять его как innerHTML, уловка заключалась в том, чтобы создать новый элемент сценария и добавить фактическое содержимое сценария как innerHTML к созданному элементу, а затем добавить этот элемент сценария к фактической цели.
<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.
Для любителей опасной жизни:
// This is the HTML with script element(s) we want to inject
var newHtml = '<b>After!</b>\r\n<' +
'script>\r\nchangeColorEverySecond();\r\n</' +
'script>';
// Here, we separate the script tags from the non-script HTML
var parts = separateScriptElementsFromHtml(newHtml);
function separateScriptElementsFromHtml(fullHtmlString) {
var inner = [], outer = [], m;
while (m = /<script>([^<]*)</script>/gi.exec(fullHtmlString)) {
outer.push(fullHtmlString.substr(0, m.index));
inner.push(m[1]);
fullHtmlString = fullHtmlString.substr(m.index + m[0].length);
}
outer.push(fullHtmlString);
return {
html: outer.join('\r\n'),
js: inner.join('\r\n')
};
}
// In 2 seconds, inject the new HTML, and run the JS
setTimeout(function(){
document.getElementsByTagName('P')[0].innerHTML = parts.html;
eval(parts.js);
}, 2000);
// This is the function inside the script tag
function changeColorEverySecond() {
document.getElementsByTagName('p')[0].style.color = getRandomColor();
setTimeout(changeColorEverySecond, 1000);
}
// Here is a fun fun function copied from:
// https://stackoverflow.com/a/1484514/2413712
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}<p>Before</p>
Лучший отвечать, который я нашел до сих пор. Я считаю, что это применимо к большинству случаев.