J'ai essayé de charger des scripts dans une page en utilisant innerHTML
sur <div>
. Il semble que le script se charge dans le DOM, mais il n'est jamais exécuté (au moins dans Firefox et Chrome). Existe-t-il un moyen d'exécuter des scripts lors de leur insertion innerHTML
?
Exemple de code:
<!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>
la source
<script>
balise avecinnerHTML
peut-être court, mais cela ne fonctionne pas. Ce n'est que du texte brut jusqu'à ce qu'il soit exécutéeval()
. Et malheureusement,eval()
n'analyse pas les balises HTML, vous vous retrouvez donc avec une chaîne de problèmes.Voici une solution très intéressante à votre problème: http://24ways.org/2005/have-your-dom-and-script-it-too
Utilisez donc ceci à la place des balises de script:
<img src="empty.gif" onload="alert('test');this.parentNode.removeChild(this);" />
la source
onload
attribut. Cela nécessite également l'existence d'un fichier supplémentaire et son chargement. La solution de momo est moins un compromis.<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
(cela ne fera pas une demande réseau) En fait ... vous n'avez PAS besoin d'une image, référencer une image non existante et au lieu d'onload
utiliseronerror
(mais cela fera une demande réseau)Voici une méthode qui remplace récursivement tous les scripts par des exécutables:
Exemple d'appel:
la source
Vous pouvez créer un script puis injecter le contenu.
Cela fonctionne dans tous les navigateurs :)
la source
document.documentElement
plutôt.<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>
éléments. Par exemple<img onerror="..." src="#">
et<body onload="...">
. Si vous voulez être technique, cela ne fonctionnera pas non plus dans les documents non HTML / SVG en raison de l'espacement des noms inexplicite.J'ai utilisé ce code, ça marche bien
la source
J'ai eu ce problème avec innerHTML, j'ai dû ajouter un script Hotjar à la balise "head" de mon application Reactjs et elle devrait s'exécuter juste après l'ajout.
L'une des bonnes solutions pour l'importation dynamique de nœuds dans la balise "head" est le module React-helment .
Il existe également une solution utile au problème proposé:
Pas de balises de script dans innerHTML!
Il s'avère que HTML5 n'autorise pas l'ajout dynamique de balises de script à l'aide de la propriété innerHTML. Donc, ce qui suit ne s'exécutera pas et il n'y aura pas d'alerte disant Bonjour tout le monde!
Ceci est documenté dans la spécification HTML5:
Mais attention, cela ne signifie pas que innerHTML est à l'abri des scripts intersites. Il est possible d'exécuter JavaScript via innerHTML sans utiliser de balises comme illustré sur la page innerHTML de MDN .
Solution: ajout dynamique de scripts
Pour ajouter dynamiquement une balise de script, vous devez créer un nouvel élément de script et l'ajouter à l'élément cible.
Vous pouvez le faire pour les scripts externes:
Et des scripts en ligne:
la source
Pour ceux qui essaient encore de le faire, non, vous ne pouvez pas injecter un script en utilisant
innerHTML
, mais il est possible de charger une chaîne dans une balise de script en utilisant unBlob
etURL.createObjectURL
.J'ai créé un exemple qui vous permet d'exécuter une chaîne en tant que script et d'obtenir le retour des «exportations» du script via une promesse:
J'ai simplifié cela à partir de mon implémentation réelle, donc aucune promesse qu'il n'y a pas de bogues. Mais le principe fonctionne.
Si vous ne vous souciez pas de récupérer une valeur après l'exécution du script, c'est encore plus facile; il suffit de laisser de côté les bits
Promise
etonload
. Vous n'avez même pas besoin d'envelopper le script ou de créer lawindow.__load_script_exports_
propriété globale .la source
Voici une fonction récursive pour définir le innerHTML d'un élément que j'utilise dans notre ad server:
Vous pouvez voir la démo ici .
la source
Vous pouvez le faire comme ceci:
la source
Voici une solution qui n'utilise pas
eval
, et fonctionne avec des scripts , des scripts liés , ainsi qu'avec des modules .La fonction accepte 3 paramètres:
la source
eval('console.log(this)')
et vous verrez la plus évidenteeval('let b=100')
.. puis essayez d'accéderb
depuis l'extérieur de l'évaluation ... bonne chance avec lui, vous allez en avoir besoinKrasimir Tsonev a une excellente solution qui surmonte tous les problèmes. Sa méthode n'a pas besoin d'utiliser eval, donc aucun problème de performance ou de sécurité n'existe. Il vous permet de définir la chaîne innerHTML contient du html avec js et de le traduire immédiatement en un élément DOM tout en exécutant les parties js qui existent le long du code. court, simple et fonctionne exactement comme vous le souhaitez.
Profitez de sa solution:
http://krasimirtsonev.com/blog/article/Convert-HTML-string-to-DOM-element
Notes IMPORTANTES:
la source
Utiliser
$(parent).html(code)
au lieu deparent.innerHTML = code
.Ce qui suit corrige également les scripts qui utilisent
document.write
et les scripts chargés via l'src
attribut. Malheureusement, même cela ne fonctionne pas avec les scripts Google AdSense.La source
la source
Essayez d'utiliser le modèle et le document.importNode. Voici un exemple:
la source
Vous pouvez également envelopper votre
<script>
comme ceci et il sera exécuté:Veuillez noter: la portée à l'intérieur
srcdoc
fait référence à l'iframe, vous devez donc utilisertop
comme dans l'exemple ci-dessus pour accéder au document parent.la source
Oui, vous pouvez le faire, mais vous devez le faire en dehors du DOM et la commande doit être correcte.
... alertera "foo". Cela ne fonctionnera pas:
Et même cela ne fonctionnera pas, car le nœud est inséré en premier:
la source
Ma solution à ce problème consiste à définir un observateur de mutation pour détecter les
<script></script>
nœuds, puis à le remplacer par un nouveau<script></script>
nœud avec le même src. Par exemple:la source
La mention de MutationObservers par Gabriel Garcia est sur la bonne voie, mais n'a pas vraiment fonctionné pour moi. Je ne sais pas si c'était à cause d'une bizarrerie du navigateur ou à cause d'une erreur de ma part, mais la version qui a fini par fonctionner pour moi était la suivante:
Bien sûr, vous devez remplacer
element_to_watch
par le nom de l'élément en cours de modification.node.parentElement.added
est utilisé pour stocker les balises de script qui sont ajoutées àdocument.head
. Dans la fonction utilisée pour charger la page externe, vous pouvez utiliser quelque chose comme le suivant pour supprimer les balises de script qui ne sont plus pertinentes:Et un exemple du début d'une fonction de chargement:
la source
MutationObserver
chaque fois qu'un élément est ajouté au document, non? Btw, je me demande pourquoi dites-vous que mon code n'est pas fonctionnel.Pour moi, le meilleur moyen est d'insérer le nouveau contenu HTML via innerHtml puis d'utiliser
SetTimeout n'est pas requis mais il fonctionne mieux. Cela a fonctionné pour moi.
la source
Je le fais chaque fois que je veux insérer dynamiquement une balise de script!
REMARQUE: ES6 utilisé
EDIT 1: Clarification pour vous les gars - J'ai vu beaucoup de réponses utilisées
appendChild
et je voulais vous faire savoir que cela fonctionne exactement commeappend
la source
Exécuter (balise Java Script) de innerHTML
Remplacez votre élément de script par div ayant un attribut de classe class = "javascript" et fermez-le avec
</div>
Ne modifiez pas le contenu que vous souhaitez exécuter (auparavant, il était dans la balise de script et maintenant il est dans la balise div)
Ajoutez un style à votre page ...
<style type="text/css"> .javascript { display: none; } </style>
Maintenant, exécutez eval en utilisant jquery (Jquery js devrait déjà être inclus)
Vous pouvez en découvrir plus ici , sur mon blog.
la source