script标签仅在插入DOM后第一次运行

时间:2011-06-09 13:51:04

标签: javascript html dom innerhtml

非常奇怪为什么脚本标签在插入dom后只运行一次。

script = document.createElement('script');
script.type = 'text/javascript'

script
//output: <script type=​"text/​javascript">​</script>​

document.body.appendChild(script);

script.innerHTML = 'console.log("Attempt one")'
//output Attempt one

script.innerHTML = 'console.log("Attempt two")'

script.innerHTML = 'console.log("Attempt three")'

//second and third attempts emit no output

有没有办法让脚本文本的其他更改能够运行?

我已经尝试将它包装成一个函数而没有成功......我找不到任何解释为什么log第一次运行而不是以下那些

3 个答案:

答案 0 :(得分:3)

这里只是澄清,上面的代码可能是一个糟糕的方法,等等。 但问题实际上是指行为以及为什么会发生这种行为。

在过去几分钟玩完之后,我发现只要每个脚本标签都附加到DOM并且有内容,javascript只会运行一次。

例如,您可以在DOM中附加script标记而不添加任何内容... 那不会激发javascript。但只要您使用innerTextinnerHTML等向该标记添加内容,它就会立即触发javascript。

很有意思的是,每个脚本标记似乎处理一个标志,每当javascript为该特定标记运行时设置为false,然后在此之后它赢了不管怎么说,再次开火。

这里有一些有趣的测试:

正常行为

var script = document.createElement('script');

document.body.appendChild(script);

script.innerHTML = 'alert("attemp one")';
// outputs alert
script.innerHTML = 'alert("attemp two")';
// no output

深度克隆节点

var clone = script.cloneNode(true);
// <script>alert("attemp two")</script>

document.body.replaceChild(clone, script);
// no output

简单克隆节点

var clone = script.cloneNode();
// <script></script>

clone.innerHTML = 'alert("attemp two")';

document.body.replaceChild(clone, script);
// no output

替换新标签

var newScript = document.createElement('script');

newScript.innerHTML = 'alert("attempt three")';

document.body.replaceChild(newScript, script);
// output alert

因此,您可以看到脚本标记将保留alreadyExecuted属性,无论原因如何,如果您通过生成精确副本来克隆它...

这让我觉得有没有办法将此标志设置为其原始初始值,而不是创建新的script标记。

但在最坏的情况下,如果你真的需要使用它。创建一个获取script的动作并不难,如果你有一些属性,则创建一个具有相同属性的新动作,然后用旧的但用新内容替换它。 javascript会像第一次一样运行。

可以轻松调用以下脚本,它将替换旧脚本标记,并通过简单地提供您希望替换内容的脚本标记来执行新的javascript。

function innerScript(element) {

    var newElement = document.createElement('script'),
        attr;

    for (attr = 0; attr < element.attributes.length; attr += 1) {
        newElement.setAttribute(element.attributes[attr].name, element.attributes[attr].value);
    }

    element.parentNode.replaceChild(newElement, element);
    return newElement;

}

答案 1 :(得分:1)

在脚本执行中的任意点更改<script /> DOM节点的内部文本不会触发重新执行整个脚本,不会。

创建新的脚本标记,或者更好地优化您的方法。你永远不应该发现自己需要注入脚本标签;相反,只需以正常方式执行这些函数调用。

答案 2 :(得分:0)

就是它的样子。您通常不必向现有标记添加新代码;要么创建新标签,要么更好地利用功能和事件。