Можно ли вставлять скрипты с помощью innerHTML?

Я попытался загрузить несколько скриптов на страницу, используя innerHTML на <div>. Похоже, что скрипт загружается в DOM, но никогда не выполняется (по крайней мере, в Firefox и Chrome). Есть ли способ заставить скрипты выполняться при их вставке с помощью innerHTML?

Образец кода:

<!DOCTYPE html>
<html>
  <body onload="document.getElementById('loader').innerHTML = '<script>alert(\'hi\')<\/script>'">
    Shouldn't an alert saying 'hi' appear?
    <div id="loader"></div>
  </body>
</html>


person Craig    schedule 29.07.2009    source источник


Ответы (22)


Вы должны использовать eval () для выполнения любого кода сценария, который вы вставили как DOM. текст.

MooTools сделает это за вас автоматически, и я уверен, что jQuery тоже (в зависимости от версии. JQuery версии 1.6+ использует eval). Это избавляет от лишних хлопот по синтаксическому анализу <script> тегов и экранированию вашего контента, а также от множества других "подводных камней".

Обычно, если вы собираетесь eval() это делать самостоятельно, вы хотите создать / отправить код сценария без какой-либо разметки HTML, такой как <script>, так как это не будет eval() должным образом.

person zombat    schedule 29.07.2009
comment
Что я действительно хочу сделать, так это загрузить внешний скрипт, а не просто оценить какой-то локальный скрипт. Добавление тега сценария с помощью innerHTML намного короче, чем создание элемента DOM сценария и добавление его в тело, и я стараюсь сделать свой код как можно короче. Вам нужно создавать элементы сценария dom и добавлять их в dom, а не просто использовать что-то вроде innerHTML? Есть ли способ сделать это с помощью document.write из функции? - person Craig; 29.07.2009
comment
Как предлагает зомбат, используйте среду Javascript для загрузки внешнего скрипта, не пытайтесь изобретать велосипед. JQuery делает это чрезвычайно простым, просто включите JQuery и вызовите: $ .getScript (url). Вы также можете предоставить функцию обратного вызова, которая будет выполняться после загрузки скрипта. - person Ariel Popovsky; 29.07.2009
comment
Ариэль права. Я ценю попытку сделать ваш код коротким, и добавление тега <script> с innerHTML может быть коротким, но это не работает. Это просто обычный текст, пока он не пройдет eval(). К сожалению, eval() не анализирует HTML-теги, поэтому в конечном итоге возникает цепочка проблем. - person zombat; 29.07.2009
comment
eval () - не лучшее решение любой проблемы. - person buley; 13.10.2011
comment
Я сам пробовал eval (). Это ужасная идея. Вы должны оценивать все это КАЖДЫЙ РАЗ. Даже если вы объявляете имя и значение переменной, вам придется каждый раз заново объявлять / повторно eval (), чтобы она работала. Это кошмар ошибок. - person Youstay Igo; 04.11.2015
comment
@buley Почему нет? - person Barrosy; 26.04.2019
comment
@Barrosy часто, но не всегда злой stackoverflow.com / questions / 197769 / - person buley; 03.05.2019

Вот метод, рекурсивно заменяющий все скрипты исполняемыми:

function nodeScriptReplace(node) {
        if ( nodeScriptIs(node) === true ) {
                node.parentNode.replaceChild( nodeScriptClone(node) , node );
        }
        else {
                var i = -1, children = node.childNodes;
                while ( ++i < children.length ) {
                      nodeScriptReplace( children[i] );
                }
        }

        return node;
}
function nodeScriptClone(node){
        var script  = document.createElement("script");
        script.text = node.innerHTML;

        var i = -1, attrs = node.attributes, attr;
        while ( ++i < attrs.length ) {                                    
              script.setAttribute( (attr = attrs[i]).name, attr.value );
        }
        return script;
}

function nodeScriptIs(node) {
        return node.tagName === 'SCRIPT';
}

Пример вызова:

nodeScriptReplace(document.getElementsByTagName("body")[0]);
person mmm    schedule 14.12.2013
comment
Я немного удивлен, что твой ответ полностью опущен. IMHO, это лучшее решение, этот метод даже позволит вам ограничить скрипты определенными URL-адресами или контентом. - person davidmh; 03.04.2014
comment
@ inf3rno делает или нет? Раньше это работало, кто-нибудь когда-нибудь утверждал что-нибудь другое? - person mmm; 19.06.2015
comment
каковы цели [0]? можете ли вы использовать nodeScriptReplace (document.getElementById (). html); - person Bao Thai; 21.04.2017
comment
@BaoThai Да. Ты сможешь. - person mmm; 05.08.2017
comment
В IWebBrowser2 не помогает; Я могу подтвердить, что теги сценария воссоздаются с помощью createElement, но я все еще не могу вызвать их с помощью InvokeScript (). - person Dave; 04.12.2017
comment
@ Дэйв, ты уверен, что у тебя есть подходящие атрибуты? rel = 'text / javascritp', например? - person mmm; 13.11.2020
comment
Я получаю сообщение об ошибке Uncaught (в обещании). TypeError: Не могу прочитать свойство length, равное undefined, но я новичок. Что я делаю неправильно? - person Katharina Schreiber; 26.11.2020
comment
@KatharinaSchreiber в этом коде нет обещаний, поэтому, вероятно, не имеет отношения к этому. - person mmm; 28.11.2020

Вот очень интересное решение вашей проблемы: http://24ways.org/2005/have-your-dom-and-script-it-too

Так что используйте это вместо тегов скрипта:

<img src="empty.gif" onload="alert('test');this.parentNode.removeChild(this);" />

person user447963    schedule 15.09.2010
comment
У меня не работает при вставке в результат ajax-запроса: Ошибка синтаксиса отсутствует; оператор перед в начале строки скрипта - person Oliver; 03.08.2014
comment
Как вы, люди, добавляете строку img src ... в код своей страницы? Вы используете document.write () или используете для этого подход document.body.innerHTML + =? У меня оба не работают :( - person Youstay Igo; 04.11.2015
comment
Не очень практично писать много кода внутри атрибута onload. Также для этого требуется, чтобы существовал и загружался дополнительный файл. Решение momo не является компромиссом. - person fregante; 10.03.2016
comment
Два недостатка: 1. Он не может вызывать какие-либо скрипты / функции, добавленные через innerHTML (вместе с этим тегом IMG), потому что они не существуют для браузера 2. Если часть встроенного кода до .removeChild () выдает исключение , элемент img не будет удален. - person user3526; 12.04.2016
comment
Одно быстрое замечание. Это решение может не дать вам точных результатов, если вы загружаете над ним изображения большего размера (так как они могут загружаться дольше, чем ваш пустой gif). - person newshorts; 30.08.2016
comment
Вы можете Base64 закодировать свое триггерное изображение как <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"> (это не будет выполнять сетевой запрос) На самом деле ... вам НЕ нужно изображение, ссылаться на несуществующее изображение и вместо onload использовать onerror (но это будет выполнять сетевой запрос ) - person Danny '365CSI' Engelman; 20.10.2016
comment
user447963 & Danny'365CSI'Engelman: Это действительно великолепно. Это то, что можно назвать взломом. Думать иначе, чтобы добиться чего-то, что иначе было бы невозможно. То, о чем вы обычно не думаете (хотя знаете об этом где-то в голове). - person StanE; 15.01.2017
comment
Самый простой в реализации и работает во всех основных браузерах (протестирован в последних версиях IE, Edge, Opera, Firefox и Chrome). У нестандартного мышления есть свои преимущества! - person Ivan; 25.09.2018
comment
@ Danny'365CSI'Engelman Ооооооо, напишите что-нибудь недопустимое в src: вызовет ошибку, но не сделает сетевой запрос: src="?" onerror="alert('Hello');this.parentNode.removeChild(this)" - person FZs; 06.05.2020

Вы можете создать сценарий, а затем ввести контент.

var g = document.createElement('script');
var s = document.getElementsByTagName('script')[0];
g.text = "alert(\"hi\");"
s.parentNode.insertBefore(g, s);

Это работает во всех браузерах :)

person Pablo Moretti    schedule 14.08.2011
comment
Если в документе нет других элементов скрипта. Вместо этого используйте document.documentElement. - person Eli Grey; 14.08.2011
comment
В этом нет необходимости, потому что вы пишете сценарий из другого сценария. <script> var g = document.createElement('script'); var s = document.getElementsByTagName('script')[0]; //reference this script g.text = "alert(\"hi\");" s.parentNode.insertBefore(g, s); </script> - person Pablo Moretti; 14.08.2011
comment
Кто сказал, что это из другого сценария? Вы можете запускать JavaScript без <script> элементов. Например. <img onerror="..." src="#"> и <body onload="...">. Если вы хотите быть техническим, это не будет работать в документах, отличных от HTML / SVG, из-за неявного пространства имен. - person Eli Grey; 15.08.2011
comment
Facebook использует ответ Пабло в своем SDK. developers.facebook.com/docs/javascript/quickstart/v2.2# загрузка - person geoyws; 08.02.2015

Я использовал этот код, он работает нормально

var arr = MyDiv.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
    eval(arr[n].innerHTML)//run script inside div
person Firas Nizam    schedule 29.04.2013
comment
Спасибо. Это устранило мою проблему с добавлением кода Disqus Universal в модальное всплывающее окно, созданное с помощью плагина TinyBox2 Jquery. - person gsinha; 06.07.2014
comment
К сожалению, это решение не работает, если сценарий содержит функции, которые будут вызываться позже. - person Jose Gómez; 16.07.2015

У меня была эта проблема с innerHTML, мне пришлось добавить сценарий Hotjar в тег «head» моего приложения Reactjs, и он должен был выполняться сразу после добавления.

Одним из хороших решений для динамического импорта узлов в тег «head» является модуль React-helment.


Также есть полезное решение предложенной проблемы:

В innerHTML нет тегов скрипта!

Оказывается, HTML5 не позволяет динамически добавлять теги скриптов с помощью свойства innerHTML. Таким образом, следующее не будет выполнено, и не будет предупреждений с сообщением Hello World!

element.innerHTML = "<script>alert('Hello World!')</script>";

Это задокументировано в спецификации HTML5:

Примечание: элементы скрипта, вставленные с помощью innerHTML, не выполняются при вставке.

Но будьте осторожны, это не означает, что innerHTML защищен от межсайтовых сценариев. Можно выполнять JavaScript через innerHTML без использования тегов, как показано на MDN. страница innerHTML.

Решение: динамическое добавление скриптов

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

Вы можете сделать это для внешних скриптов:

var newScript = document.createElement("script");
newScript.src = "http://www.example.com/my-script.js";
target.appendChild(newScript);

И встроенные скрипты:

var newScript = document.createElement("script");
var inlineScript = document.createTextNode("alert('Hello World!');");
newScript.appendChild(inlineScript); 
target.appendChild(newScript);
person p.daniel    schedule 11.11.2019
comment
Ваш newScript элемент имеет интерфейс HTMLScriptElement, поэтому вы можете просто установить встроенный код с newScript.text = "alert('Hello World!')"; не требует создания и добавления нового текстового узла. - person Martin; 23.07.2020
comment
@Martin: Конечно, в мире программирования есть много разных способов реализовать что-то! Кроме того, это более понятно и удобно :). - person p.daniel; 29.03.2021

Я делаю это каждый раз, когда хочу динамически вставить тег скрипта!

  const html =
    `<script>
        alert('???? there ! Wanna grab a ????'); 
    </script>`;

  const scriptEl = document.createRange().createContextualFragment(html);
  parent.append(scriptEl);

ПРИМЕЧАНИЕ. Используется ES6

РЕДАКТИРОВАТЬ 1: Разъяснение для вас, ребята - я видел много ответов, использующих appendChild, и хотел, чтобы вы, ребята, знали, что он работает точно так же, как append

person Tilak Maddy    schedule 29.06.2020

Для тех, кто все еще пытается это сделать, нет, вы не можете внедрить скрипт, используя innerHTML, но можно загрузить строку в тег скрипта, используя Blob и URL.createObjectURL.

Я создал пример, который позволяет вам запустить строку как скрипт и получить «экспорт» скрипта, возвращенный через обещание:

function loadScript(scriptContent, moduleId) {
    // create the script tag
    var scriptElement = document.createElement('SCRIPT');

    // create a promise which will resolve to the script's 'exports'
    // (i.e., the value returned by the script)
    var promise = new Promise(function(resolve) {
        scriptElement.onload = function() {
            var exports = window["__loadScript_exports_" + moduleId];
            delete window["__loadScript_exports_" + moduleId];
            resolve(exports);
        }
    });

    // wrap the script contents to expose exports through a special property
    // the promise will access the exports this way
    var wrappedScriptContent =
        "(function() { window['__loadScript_exports_" + moduleId + "'] = " + 
        scriptContent + "})()";

    // create a blob from the wrapped script content
    var scriptBlob = new Blob([wrappedScriptContent], {type: 'text/javascript'});

    // set the id attribute
    scriptElement.id = "__loadScript_module_" + moduleId;

    // set the src attribute to the blob's object url 
    // (this is the part that makes it work)
    scriptElement.src = URL.createObjectURL(scriptBlob);

    // append the script element
    document.body.appendChild(scriptElement);

    // return the promise, which will resolve to the script's exports
    return promise;
}

...

function doTheThing() {
    // no evals
    loadScript('5 + 5').then(function(exports) {
         // should log 10
        console.log(exports)
    });
}

Я упростил это по сравнению с моей реальной реализацией, поэтому никаких обещаний, что в нем нет никаких ошибок. Но принцип работает.

Если вы не заботитесь о возвращении какого-либо значения после запуска сценария, это еще проще; просто оставьте биты Promise и onload. Вам даже не нужно оборачивать сценарий или создавать глобальное свойство window.__load_script_exports_.

person JayArby    schedule 04.11.2016
comment
Я просто попробовал, и он работает на chrome 57. innerHTML в теге скрипта выполняет текст. - person iPherian; 22.04.2017
comment
Что интересно, раньше не работало. Интересно, кроссбраузерно ли это поведение или только в chrome 57. - person JayArby; 03.05.2017

Вот рекурсивная функция для установки innerHTML элемента, который я использую на нашем рекламном сервере:

// o: container to set the innerHTML
// html: html text to set.
// clear: if true, the container is cleared first (children removed)
function setHTML(o, html, clear) {
    if (clear) o.innerHTML = "";

    // Generate a parseable object with the html:
    var dv = document.createElement("div");
    dv.innerHTML = html;

    // Handle edge case where innerHTML contains no tags, just text:
    if (dv.children.length===0){ o.innerHTML = html; return; }

    for (var i = 0; i < dv.children.length; i++) {
        var c = dv.children[i];

        // n: new node with the same type as c
        var n = document.createElement(c.nodeName);

        // copy all attributes from c to n
        for (var j = 0; j < c.attributes.length; j++)
            n.setAttribute(c.attributes[j].nodeName, c.attributes[j].nodeValue);

        // If current node is a leaf, just copy the appropriate property (text or innerHTML)
        if (c.children.length == 0)
        {
            switch (c.nodeName)
            {
                case "SCRIPT":
                    if (c.text) n.text = c.text;
                    break;
                default:
                    if (c.innerHTML) n.innerHTML = c.innerHTML;
                    break;
            }
        }
        // If current node has sub nodes, call itself recursively:
        else setHTML(n, c.innerHTML, false);
        o.appendChild(n);
    }
}

Вы можете увидеть демонстрацию здесь.

person Adnan Korkmaz    schedule 02.05.2017

Здесь решение, которое не использует eval и работает с сценариями, связанными сценариями, а также с модулями.

Функция принимает 3 параметра:

  • html: строка с HTML-кодом для вставки.
  • dest: ссылка на целевой элемент
  • append: логический флаг для включения добавления в конец целевого элемента html.
function insertHTML(html, dest, append=false){
    // if no append is requested, clear the target element
    if(!append) dest.innerHTML = '';
    // create a temporary container and insert provided HTML code
    let container = document.createElement('div');
    container.innerHTML = html;
    // cache a reference to all the scripts in the container
    let scripts = container.querySelectorAll('script');
    // get all child elements and clone them in the target element
    let nodes = container.childNodes;
    for( let i=0; i< nodes.length; i++) dest.appendChild( nodes[i].cloneNode(true) );
    // force the found scripts to execute...
    for( let i=0; i< scripts.length; i++){
        let script = document.createElement('script');
        script.type = scripts[i].type || 'text/javascript';
        if( scripts[i].hasAttribute('src') ) script.src = scripts[i].src;
        script.innerHTML = scripts[i].innerHTML;
        document.head.appendChild(script);
        document.head.removeChild(script);
    }
    // done!
    return true;
}
person colxi    schedule 22.05.2019
comment
Я имею в виду ... Добавление тега скрипта с содержимым кода - это оценка, не так ли? - person Kevin B; 23.07.2019
comment
@KevinB Есть пресловутые различия ... попробуйте eval('console.log(this)'), и вы увидите наиболее очевидное - person colxi; 24.07.2019
comment
так контекст другой, а? это все еще просто оценка. - person Kevin B; 24.07.2019
comment
@KevinB Нет, это не оценка. Попробуйте это eval('let b=100') .. а затем попробуйте получить доступ к b извне eval .... удачи вам, он вам понадобится - person colxi; 24.07.2019
comment
Работает на меня. Ваше здоровье - person Bezzzo; 18.03.2020

Сделать это можно так:

var mydiv = document.getElementById("mydiv");
var content = "<script>alert(\"hi\");<\/script>";

mydiv.innerHTML = content;
var scripts = mydiv.getElementsByTagName("script");
for (var i = 0; i < scripts.length; i++) {
    eval(scripts[i].innerText);
}
person Jake    schedule 26.06.2018

Отфильтруйте теги сценария и запустите каждый из них с помощью eval

var tmp=  document.createElement('div');
tmp.innerHTML = '<script>alert("hello")></script>';
[...tmp.children].filter(x => x.nodeName === 'SCRIPT').forEach(x => eval(x.innerText));
person Ozan ERTÜRK    schedule 07.01.2021

Да, вы можете, но вы должны делать это вне DOM, и порядок должен быть правильным.

var scr = '<scr'+'ipt>alert("foo")</scr'+'ipt>';
window.onload = function(){
    var n = document.createElement("div");
    n.innerHTML = scr;
    document.body.appendChild(n);
}

... предупредит 'foo'. Это не сработает:

document.getElementById("myDiv").innerHTML = scr;

И даже это не сработает, потому что узел вставляется первым:

var scr = '<scr'+'ipt>alert("foo")</scr'+'ipt>';
window.onload = function(){
    var n = document.createElement("div");
    document.body.appendChild(n);
    n.innerHTML = scr;  
}
person mwilcox    schedule 29.07.2009
comment
Для чего это стоит: похоже, это не работает в текущих браузерах. - person Wichert Akkerman; 31.01.2012

У Красимира Цонева есть отличное решение, которое преодолевает все проблемы. Его метод не требует использования eval, поэтому нет проблем с производительностью или безопасностью. Он позволяет вам установить строку innerHTML, содержащую html с js, и немедленно преобразовать ее в элемент DOM, а также выполнить части js, существующие в коде. коротко, просто и работает именно так, как вы хотите.

Наслаждайтесь его решением:

http://krasimirtsonev.com/blog/article/Convert-HTML-string-to-DOM-element

Важные заметки:

  1. Вам нужно обернуть целевой элемент тегом div
  2. Вам нужно обернуть строку src тегом div.
  3. Если вы пишете строку src напрямую и она включает части js, обратите внимание на правильность написания закрывающих тегов скрипта (с помощью \ before /), поскольку это строка.
person user3198805    schedule 28.01.2014

Используйте $(parent).html(code) вместо parent.innerHTML = code.

Следующее также исправляет скрипты, которые используют document.write, и скрипты, загруженные через атрибут src. К сожалению, даже это не работает со скриптами Google AdSense.

var oldDocumentWrite = document.write;
var oldDocumentWriteln = document.writeln;
try {
    document.write = function(code) {
        $(parent).append(code);
    }
    document.writeln = function(code) {
        document.write(code + "<br/>");
    }
    $(parent).html(html); 
} finally {
    $(window).load(function() {
        document.write = oldDocumentWrite
        document.writeln = oldDocumentWriteln
    })
}

Источник

person iirekm    schedule 07.05.2014
comment
немного поздно, но любой, кто может использовать этот метод, заметит, что в JQuery вам нужно загружать свои скрипты, используя $ .loadScript (url), а не ‹script src = url› ‹/script› - последнее вызовет устаревшее Синхронная ошибка XMLHttpRequest в браузерах. - person Stavm; 23.11.2016

Попробуйте использовать шаблон и document.importNode. Вот пример:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<h1 id="hello_world">Sample</h1>
<script type="text/javascript">
 var div = document.createElement("div");
  var t = document.createElement('template');
  t.innerHTML =  "Check Console tab for javascript output: Hello world!!!<br/><script type='text/javascript' >console.log('Hello world!!!');<\/script>";
  
  for (var i=0; i < t.content.childNodes.length; i++){
    var node = document.importNode(t.content.childNodes[i], true);
    div.appendChild(node);
  }
 document.body.appendChild(div);
</script>
 
</body>
</html>

person Gray    schedule 09.02.2018
comment
Это не работает с Microsoft Edge, есть ли другое решение? - person Soul; 23.03.2018

Вы также можете обернуть свой <script> вот так, и он будет выполнен:

<your target node>.innerHTML = '<iframe srcdoc="<script>alert(top.document.title);</script>"></iframe>';

Обратите внимание: область внутри srcdoc относится к iframe, поэтому вы должны использовать top, как в примере выше, для доступа к родительскому документу.

person naden    schedule 06.09.2019

Мое решение этой проблемы - настроить Mutation Observer для обнаруживать <script></script> узлы и затем заменять его новым <script></script> узлом с тем же src. Например:

let parentNode = /* node to observe */ void 0
let observer = new MutationObserver(mutations=>{
    mutations.map(mutation=>{
        Array.from(mutation.addedNodes).map(node=>{
            if ( node.parentNode == parentNode ) {
                let scripts = node.getElementsByTagName('script')
                Array.from(scripts).map(script=>{
                    let src = script.src
                    script = document.createElement('script')
                    script.src = src
                    return script
                })
            }
        })
    })
})
observer.observe(document.body, {childList: true, subtree: true});
person gabriel garcia    schedule 06.10.2017
comment
Спасибо, что проголосовали против меня, не объясняя почему. Всех люблю. - person gabriel garcia; 16.11.2018
comment
Объяснение: этот фрагмент (добавленный непосредственно в HTML) гарантирует, что любой будущий внешний скрипт, добавленный как innerHTML, будет проанализирован. Я считаю это хорошей универсальной идеей, но я не проголосовал за нее из-за опасений, что скрипты, добавленные document.createElement, могут быть выполнены дважды? Меня также пугает изменение мутировавшего объекта - я не уверен, что в некоторых случаях это не могло создать бесконечный цикл. - person Jan Turoň; 20.08.2020

Упоминание Габриэлем Гарсией о MutationObservers находится на правильном пути, но не совсем сработало для меня. Я не уверен, было ли это из-за причуды браузера или из-за ошибки с моей стороны, но версия, которая в конечном итоге сработала для меня, была следующей:

document.addEventListener("DOMContentLoaded", function(event) {
    var observer = new MutationObserver(mutations=>{
        mutations.map(mutation=>{
            Array.from(mutation.addedNodes).map(node=>{
                if (node.tagName === "SCRIPT") {
                    var s = document.createElement("script");
                    s.text=node.text;
                    if (typeof(node.parentElement.added) === 'undefined')
                        node.parentElement.added = [];
                    node.parentElement.added[node.parentElement.added.length] = s;
                    node.parentElement.removeChild(node);
                    document.head.appendChild(s);
                }
            })
        })
    })
    observer.observe(document.getElementById("element_to_watch"), {childList: true, subtree: true,attributes: false});
};

Конечно, вы должны заменить element_to_watch именем изменяемого элемента.

node.parentElement.added используется для хранения тегов сценария, добавленных в document.head. В функции, используемой для загрузки внешней страницы, вы можете использовать что-то вроде следующего, чтобы удалить больше не актуальные теги скрипта:

function freeScripts(node){
    if (node === null)
        return;
    if (typeof(node.added) === 'object') {
        for (var script in node.added) {
            document.head.removeChild(node.added[script]);
        }
        node.added = {};
    }
    for (var child in node.children) {
        freeScripts(node.children[child]);
    }
}

И пример начала функции загрузки:

function load(url, id, replace) {
    if (document.getElementById(id) === null) {
        console.error("Element of ID "+id + " does not exist!");
        return;
    }
    freeScripts(document.getElementById(id));
    var xhttp = new XMLHttpRequest();
    // proceed to load in the page and modify innerHTML
}
person pixelherodev    schedule 13.10.2018
comment
Вы заметили, что добавляете новый MutationObserver каждый раз, когда элемент добавляется к документу, верно? Кстати, мне интересно, почему вы говорите, что мой код не работает. - person gabriel garcia; 14.06.2019
comment
@gabrielgarcia Я сказал, что ваш код не работает, потому что я его пробовал, и он просто не работал. Глядя на это сейчас, вполне возможно, что это было на мне, а не на тебе, и я искренне прошу прощения за то, как я это сформулировал. Исправляем это сейчас. - person pixelherodev; 20.06.2019
comment
re: добавление MutationObserver каждый раз, когда элемент добавляется в документ, о чем вы говорите? DOMContentLoaded, я цитирую здесь MDN, срабатывает, когда исходный HTML-документ был полностью загружен и проанализирован, не дожидаясь завершения загрузки таблиц стилей, изображений и подфреймов. Это один раз, и только один раз. Кроме того, этот скрипт работает без проблем на моем сайте, и отладка показывает, что это происходит только один раз, так что это один раз как на практике, так и в теории. - person pixelherodev; 20.06.2019
comment
Вы правы ... Я ошиблась. Мои извинения. - person gabriel garcia; 21.06.2019
comment
@gabrielgarcia Не проблема :) - person pixelherodev; 23.06.2019

Основываясь на комментарии Дэнни '365CSI' Энгельмана, вот универсальное решение:

<script>
  alert("This script always runs.");
  script01 = true;
</script>
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
 onload="if(typeof script01==='undefined') eval(this.previousElementSibling.innerHTML)">

Используйте его как innerHTML (т.е. загруженный XMLHttpRequest) или напрямую (т.е. вставленный сервером PHP), скрипт всегда загружается один раз.

Объяснение: скрипт, загруженный как innerHTML, не выполняется, но атрибут содержимого загрузки выполняется. Если сценарий не был выполнен (добавлен как innerHTML), сценарий выполняется в событии загрузки изображения. Если скрипт был загружен (добавлен серверной частью), тогда определяется переменная script01, и onload не будет запускать скрипт во второй раз.

person Jan Turoň    schedule 20.08.2020
comment
tnx, это был ответ 2016 года. Я бы сейчас сделал: <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'/>" onload="console.log(21,this)"/> - person Danny '365CSI' Engelman; 22.08.2020

Выполнить тег (Java Script) из innerHTML

Замените элемент сценария на div с атрибутом класса class = "javascript" и закройте его с помощью </div>

Не меняйте контент, который вы хотите выполнить (раньше он был в теге скрипта, а теперь в теге div)

Добавьте стиль на свою страницу ...

<style type="text/css"> .javascript { display: none; } </style>

Теперь запустите eval с помощью jquery (Jquery js уже должен быть включен)

   $('.javascript').each(function() {
      eval($(this).text());

    });`

Вы можете узнать больше здесь, в моем блоге.

person Knowledge Serve    schedule 22.01.2013

Для меня лучший способ - вставить новый HTML-контент через innerHtml, а затем использовать

setTimeout(() => {
        var script_el = document.createElement("script")
        script_el.src = 'script-to-add.js'
        document.body.appendChild(script_el)
    }, 500)

SetTimeout не требуется, но работает лучше. Это сработало для меня.

person Luis Tiago Flores Cristóvão    schedule 25.04.2020