Tohle bylo triviální.
Jak je uvedeno ve specifikaci (8.4 Analýza fragmentů HTML a 8.2.3.5 Jiné příznaky stavu analýzy), citovat:
při použití innerHTML
prohlížeč bude
-
Vytvořte nový uzel Dokument a označte jej jako dokument HTML.
-
Pokud existuje kontextový prvek a dokument kontextového prvku je v režimu quirks, nechte Dokument v režimu quirks. V opačném případě, pokud existuje kontextový prvek a prvek Document of thecontext je v režimu omezených quirků, pak nechte dokument v režimu neomezených vtipů. V opačném případě ponechte dokument v režimu bez výstředností.
-
Vytvořte nový analyzátor HTML a přiřaďte jej k právě vytvořenému uzlu Document....
a při analýze <script>
uvnitř
Příznak skriptování je nastaven na "enabled", pokud bylo skriptování povoleno pro dokument, ke kterému je analyzátor přidružen, když byl analyzátor vytvořen, a v opačném případě na "disabled".
Příznak skriptování lze povolit, i když byl analyzátor původně vytvořen pro algoritmus analýzy fragmentů HTML, i když se v takovém případě skriptové prvky nespustí.
Nebude tedy spuštěn, pokud do něj vložíte innerHTML
.
A pomocí innerHTML
zabrání té <script>
prvek vytvořený z trvalého provádění.
Jak je uvedeno ve specifikaci (4.3.1 Element script,) quote:
Dynamická změna atributů src, type, charset, async a defer nemá žádný přímý účinek; tyto atributy se používají pouze v určitých časech popsaných níže.
Na závěr níže popsané to znamená, že analyzuje pouze src
atribut při vstřikování <script>
na document
(bez ohledu na to, včetně dočasného vytvořeného při použití innerHTML
.)
Pokud tedy chcete do dokumentu vložit skript a spustit jej, musíte použít script = document.createElement('script')
.
Nastavte jeho atributy jako src
a type
, případně obsah uvnitř (pomocí script.appendChild(document.createTextNode(content))
), pak jej připojte k document.body
.
Místo toho můžete zkusit toto:
var wrap = document.createElement('div');
var scr = document.createElement('script');
scr.src = scriptUrl;
scr.type = 'text/javascript';
wrap.appendChild(scr);
document.body.appendChild(wrap);
Vytvořením značky skriptu explicitně říkáte JS, že innerHTML není text, ale je to spustitelný skript.
Možné řešení, když nemáte kontrolu nad mechanismem vkládání a jste nuceni používat innerHTML s script
beacons, je přestavět DOM uzly z těch "duchů".
Toto je opakující se problém v odvětví reklamních technologií, ve kterém mnoho automatizovaných systémů duplikuje libovolný HTML kód (aka. adservers ^^).
v Chrome funguje dobře:
var s = wrap.getElementsByTagName('script');
for (var i = 0; i < s.length ; i++) {
var node=s[i], parent=node.parentElement, d = document.createElement('script');
d.async=node.async;
d.src=node.src;
parent.insertBefore(d,node);
parent.removeChild(node);
}
(můžete to otestovat v JSFiddle)