我可以动态地向现有的脚本元素添加JavaScript吗?

20

我想动态地向现有的脚本元素添加 JavaScript,类似于:

var se = document.createElement('script');
se.setAttribute('type', 'text/javascript');
se.innerHTML = 'alert(1)';
document.getElementsByTagName('head').item(0).appendChild(se);

有趣的部分是 se.innerHTML = 'alert(1)';,那它是否有效?如果无效,我该如何正确地做?


2
我尝试过,在第一次添加<script>元素后(使用document.getElementsByTagName('head').item(0).appendChild(se);),它会执行,但是它不会响应任何进一步的.innerHTML更改,你将不得不再添加另一个<script>元素。 - aularon
3个回答

24

所有浏览器都支持javascript的text属性,在文档中添加一个没有src属性的新script元素时,将会评估该文本。

在某些浏览器中,innerHTML或向脚本元素添加子节点并不会评估脚本。

function addCode(code){
    var JS= document.createElement('script');
    JS.text= code;
    document.body.appendChild(JS);
}

//测试用例

var s= 'document.body.ondblclick=function(e){\n'+
'e=window.event? event.srcElement:e.target;\n'+
'alert(e.id || e.tagName);\n'+
'}\nalert("ready to double click!");';

addCode(s);

当所有其他注入代码到我的页面(加载后)的方法都失败时,它可以完美地工作!!! - Youstay Igo

11

这并不是将JavaScript添加到现有脚本元素中,而是创建一个新的脚本元素并将其添加到文档中。

在现代浏览器中可以使用此方法,但通常情况下,除非您确实需要在全局上下文中执行某些变量中的代码(因此无法使用new Function()或在函数内部使用eval),否则不建议这样做。

使用场景是什么?您真的必须这样做吗?

如果您尝试通过编写已经存在于文档中的<script>的文本内容来更改脚本的内容,则不会导致新脚本内容被运行,它只会更改DOM的内容。当操作<script>元素时,导致新脚本被运行的确切情况因浏览器而异(虽然HTML5 正在 尝试对其进行标准化);目前最好避免除了创建和附加新脚本之外的任何其他操作。(如果可能的话,最好完全避免编写<script>脚本。)

设置innerHTML会起作用;RoToRa的使用createTextNode方法更好。对于旧式HTML文档中的<script>innerHTML实际上与createTextNode做的事情相同,因为<script>是一个不能包含标记的CDATA元素。尽管如此,在作为XML提供的XHTML中,避免innerHTML和它的转义问题并只想设置普通文本时,通常更加干净。

此外,你可以使用[0]而不是item(0)(这是JavaScript DOM绑定的一部分),并且通常应避免使用getAttribute/setAttribute;使用DOM HTML属性,例如se.type=...,它们更易读,在IE中更不容易出现错误(尽管IE的错误不会影响您的type属性)。


+1 eval似乎是做这件事的合理方式。然而,对于从服务器传来的任何内容进行eval操作时一定要非常谨慎。 - Joeri Hendrickx
请将以下与编程有关的内容从英语翻译成中文。仅返回已翻译的文本:“+1”表示赞同最后一段中要求使用情况和建议。 - RoToRa
+1 @bobince,相关问题。如果解释器已经通过了head部分,然后在body的末尾,我创建了新的script元素并将其附加到head上-它仍然会运行脚本(即使async=false)。这让我想问:脚本是否被处理得不同?(我的意思是-Head部分已经被消化,未来附加的脚本仍然运行)http://jsbin.com/EraMuKE/15/edit - Royi Namir
@Royi:是的,脚本可以在DOM的任何位置注入并运行。(尽管在不同的浏览器中,活动DOM的定义略有不同,但文档的<head>元素始终有效。)这种工作方式背后并没有必然的思考过程。脚本插入不是一个经过精心设计的功能,只是IE所做的事情,其他浏览器效仿了它(IE是第一个实现我们所知道的完全交互式DOM的浏览器)。 - bobince
请问 "active dom" 是什么意思? - Royi Namir
在一些浏览器中,只有插入到页面文档的后代节点中的脚本才会执行。如果我没记错的话,在IE中,即使是插入到断开连接的节点,脚本仍然会执行。 - bobince

4

如果文本中包含任何可以解释为HTML的内容,例如<,使用innerHTML将会出现错误。更好的方法是附加一个(或多个)文本节点:

var se = document.createElement('script');
se.setAttribute('type', 'text/javascript');
se.appendChild(document.createTextNode('alert(1)'));
document.getElementsByTagName('head').item(0).appendChild(se);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接