Próbowałem załadować kilka skryptów do strony przy użyciu innerHTML
na zasadzie <div>
. Wygląda na to, że skrypt ładuje się do DOM, ale nigdy nie jest wykonywany (przynajmniej w Firefox i Chrome). Czy istnieje sposób na wykonanie skryptów podczas ich wstawianiainnerHTML
?
Przykładowy kod:
<!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>
źródło
<script>
taguinnerHTML
może być krótkie, ale to nie działa. To wszystko jest zwykłym tekstem, dopóki nie zostanie wyświetloneeval()
. I niestetyeval()
nie analizuje tagów HTML, więc powstaje szereg problemów.Oto bardzo interesujące rozwiązanie twojego problemu: http://24ways.org/2005/have-your-dom-and-script-it-too
Więc użyj tego zamiast tagów skryptu:
<img src="empty.gif" onload="alert('test');this.parentNode.removeChild(this);" />
źródło
onload
atrybucie. Wymaga to również dodatkowego pliku, aby istniał i został załadowany. Rozwiązanie momo jest mniejszym kompromisem.<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
(to nie wykona żądania sieciowego) Właściwie ... NIE potrzebujesz obrazu, odwołaj się do nieistniejącego obrazu i zamiast tegoonload
użyjonerror
(ale spowoduje to żądanie sieciowe)Oto metoda, która rekurencyjnie zastępuje wszystkie skrypty skryptami wykonywalnymi:
Przykładowe wywołanie:
źródło
Możesz utworzyć skrypt, a następnie wstrzyknąć zawartość.
Działa to we wszystkich przeglądarkach :)
źródło
document.documentElement
zamiast tego.<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>
<script>
elementów. Np<img onerror="..." src="#">
a<body onload="...">
. Jeśli chcesz być techniczny, nie będzie to działać w dokumentach innych niż HTML / SVG z powodu niejawnej przestrzeni nazw.Użyłem tego kodu, działa dobrze
źródło
Miałem ten problem z innerHTML, musiałem dołączyć skrypt Hotjar do tagu „head” mojej aplikacji Reactjs i musiałby on zostać wykonany zaraz po dołączeniu.
Jednym z dobrych rozwiązań dla dynamicznego importu węzła do znacznika „head” jest moduł React-helment .
Istnieje również przydatne rozwiązanie proponowanego problemu:
Brak tagów skryptowych w innerHTML!
Okazuje się, że HTML5 nie pozwala na dynamiczne dodawanie znaczników skryptu za pomocą właściwości innerHTML. Tak więc poniższe polecenia nie zostaną wykonane i nie będzie ostrzeżenia o treści Hello World!
Jest to udokumentowane w specyfikacji HTML5:
Ale uwaga, nie oznacza to, że innerHTML jest bezpieczny przed skryptami krzyżowymi. Możliwe jest wykonanie JavaScript za pośrednictwem innerHTML bez użycia tagów, jak pokazano na stronie innerHTML MDN .
Rozwiązanie: Dynamiczne dodawanie skryptów
Aby dynamicznie dodać znacznik skryptu, musisz utworzyć nowy element skryptu i dołączyć go do elementu docelowego.
Możesz to zrobić dla zewnętrznych skryptów:
I wbudowane skrypty:
źródło
Dla każdego, kto wciąż próbuje to zrobić, nie, nie możesz wstrzyknąć skryptu za pomocą
innerHTML
, ale można załadować ciąg do znacznika skryptu za pomocąBlob
aURL.createObjectURL
.Stworzyłem przykład, który pozwala uruchomić ciąg znaków jako skrypt i uzyskać zwrot eksportu tego skryptu poprzez obietnicę:
Uprościłem to z mojej faktycznej implementacji, więc nie obiecuję, że nie ma w tym żadnych błędów. Ale zasada działa.
Jeśli nie chcesz odzyskać żadnej wartości po uruchomieniu skryptu, jest to jeszcze łatwiejsze; po prostu pominąć
Promise
ionload
bity. Nie musisz nawet owijać skryptu ani tworzyćwindow.__load_script_exports_
właściwości globalnej .źródło
Oto funkcja rekurencyjna, aby ustawić innerHTML elementu, którego używam na naszym serwerze reklam:
Można zobaczyć demo tutaj .
źródło
Możesz to zrobić w następujący sposób:
źródło
Tutaj rozwiązanie, które nie używa
eval
i działa ze skryptami , połączonymi skryptami , a także z modułami .Funkcja przyjmuje 3 parametry:
źródło
eval('console.log(this)')
a zobaczysz najbardziej oczywistąeval('let b=100')
... a potem spróbuj uzyskać dostępb
spoza eval .... powodzenia, będziesz go potrzebowaćKrasimir Tsonev ma świetne rozwiązanie, które rozwiązuje wszystkie problemy. Jego metoda nie wymaga użycia eval, więc nie występują problemy z wydajnością ani bezpieczeństwem. Pozwala ci ustawić ciąg innerHTML zawierający html z js i natychmiast przetłumaczyć go na element DOM, jednocześnie wykonując części js znajdujące się wzdłuż kodu. krótki, prosty i działa dokładnie tak, jak chcesz.
Ciesz się jego rozwiązaniem:
http://krasimirtsonev.com/blog/article/Convert-HTML-string-to-DOM-element
Ważne notatki:
źródło
Użyj
$(parent).html(code)
zamiastparent.innerHTML = code
.Poniżej naprawiono także używane
document.write
skrypty i skrypty ładowane za pomocąsrc
atrybutu. Niestety nawet to nie działa ze skryptami Google AdSense.Źródło
źródło
Spróbuj użyć szablonu i document.importNode. Oto przykład:
źródło
Możesz również owinąć swój w
<script>
ten sposób, a zostanie on wykonany:Uwaga: zakres wewnątrz
srcdoc
odnosi się do elementu iframe, więctop
aby uzyskać dostęp do dokumentu nadrzędnego, należy użyć polecenia z powyższego przykładu.źródło
Robię to za każdym razem, gdy chcę dynamicznie wstawiać znacznik skryptu!
UWAGA: zastosowano ES6
EDYCJA 1: Wyjaśnienie dla was - widziałem wiele używanych odpowiedzi
appendChild
i chciałem poinformować was, że działa dokładnie tak, jakappend
źródło
Tak, możesz, ale musisz to zrobić poza DOM, a zamówienie musi być prawidłowe.
... zaalarmuje „foo”. To nie zadziała:
I nawet to nie zadziała, ponieważ węzeł jest wstawiany jako pierwszy:
źródło
Moim rozwiązaniem tego problemu jest ustawienie Mutation Observer do wykrywania
<script></script>
węzłów, a następnie zastąpienie go nowym<script></script>
węzłem z tym samym kodem SRC. Na przykład:źródło
Wspomnienie Gabriela Garcii o MutationObservers jest na dobrej drodze, ale nie całkiem dla mnie zadziałało. Nie jestem pewien, czy było to spowodowane dziwactwem przeglądarki, czy też błędem po mojej stronie, ale wersja, która ostatecznie dla mnie działała, była następująca:
Oczywiście powinieneś zastąpić
element_to_watch
nazwą modyfikowanego elementu.node.parentElement.added
służy do przechowywania dodawanych tagów skryptudocument.head
. W funkcji używanej do wczytywania strony zewnętrznej możesz użyć czegoś takiego jak poniżej, aby usunąć niepotrzebne tagi skryptu:I przykład początku funkcji ładowania:
źródło
MutationObserver
każdym razem, gdy element jest dodawany do dokumentu, prawda? Przy okazji, zastanawiam się, dlaczego mówisz, że mój kod nie działa.Dla mnie najlepszym sposobem jest wstawienie nowej zawartości HTML przez innerHtml, a następnie użycie
SetTimeout nie jest wymagany, ale działa lepiej. To zadziałało dla mnie.
źródło
Wykonaj (Java Script) znacznik z innerHTML
Zamień element skryptu na div mający atrybut class class = "javascript" i zamknij go
</div>
Nie zmieniaj treści, którą chcesz uruchomić (wcześniej była w znaczniku skryptowym, a teraz w znaczniku div)
Dodaj styl na swojej stronie ...
<style type="text/css"> .javascript { display: none; } </style>
Teraz uruchom eval za pomocą jquery (Jquery js powinno być już uwzględnione)
Możesz odkryć więcej tutaj , na moim blogu.
źródło