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

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

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

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

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

Лучший отвечать, который я нашел до сих пор. Я считаю, что это применимо к большинству случаев.

gdrt 23.04.2020 15:07
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
38
1
48 234
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Вам не нужно использовать регулярное выражение, если вы используете ответ для заполнения 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, но если пользователи не могут войти на сайт, не беспокойтесь.

wp-overwatch.com 30.11.2015 22:33

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

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

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

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

Было бы очень хорошо, если бы вы объяснили, как динамически вставлять каждый узел.

mandza 04.06.2014 14:53
Ответ принят как подходящий

Скрипт, добавленный путем установки свойства 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.

Eddie 26.09.2008 21:13

Вы можете использовать одну из популярных библиотек 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>

Другие вопросы по теме