插入并执行JavaScript

3

我有一个JavaScript变量:

var foo='<script type="text/javascript">alert("Hello World");<\/script>'  

变量通过element.innerHTML=foo;插入页面后,大约在页面加载后10秒钟触发事件。是否有一种方法可以在插入后立即执行“alert”函数?

3
你插入标签的方式不是代码被设置但未被调用的情况,而是根本没有被评估。(如果有评估,alert就会立即发生。)如果你提供更多上下文信息,几乎肯定有更好的方法来实现你想要的效果。 - T.J. Crowder
我很抱歉,这是我唯一能做到的方式(通过插入变量),因为“foo”通常是一个对象。 - lvil
@Ivil:如果您能提供更多的上下文信息,我们可能可以更好地指导您。 - T.J. Crowder
1
@Anonymouse:innerHTML正在标准化过程中,并且在跨浏览器方面比许多其他东西更好--只是不适用于此(脚本注入)。如果您尝试使用它创建无效的DOM结构(例如将divinnerHTML设置为“<tr><td>Hi there</td></tr>”),则可靠性会大大降低,但除了脚本、无效结构以及旧浏览器中某些表单字段的奇怪行为之外,它非常可靠。 - T.J. Crowder
@Anonymouse:是的,innerHTML 很容易被滥用。实际上,每当我看到 xyz.innerHTML += "mumble"; 这样的代码时,我都会皱眉。:-) 但是,如果你知道自己在做什么,它在进行整体替换时非常有用。而且,在 script 元素上根本不需要任何属性,除非你使用的不是 JavaScript,或者(对于内联 script 标记)如果你想要在支持它的浏览器中使用 deferasync - T.J. Crowder
显示剩余6条评论
2个回答

5
如果您绝对必须将JavaScript代码放入字符串并执行,那么基本上必须使用eval或类似的eval机制。在多年的JavaScript编程中,我从未不得不使用它,我建议您看看是否有其他方法来实现您的实际目标。
所以,在这里,您需要剥离脚本标记内容,然后仅eval代码,例如:
var script = foo.replace(/^<script[^>]*>/, "").replace(/<\/script>$/, "");
eval(script);
// Or window.evalInGlobalScope(script); // -- See below

显然,你必须确保信任字符串的来源,因为你正在执行其中的代码。eval是一个棘手的东西,它在上下文和范围方面玩弄非常奇怪的游戏。如果你需要类似于添加脚本标记到页面后得到的样子,这里有一个跨浏览器的函数可以实现(来自于我在 Stack Overflow 上回答另一个问题的答案)。
window.evalInGlobalScope = (function() {
    var fname, scr;

    // Get a unique function name
    do {
        fname = "__eval_in_global_test_" + Math.floor(Math.random() * 100000);
    }
    while (typeof window[fname] !== 'undefined');

    // Create test script
    scr = "function " + fname + "() { }";

    // Return the first function that works:
    return test(evalInGlobalScope_execScript) ||
           test(evalInGlobalScope_windowEval) ||
           test(evalInGlobalScope_theHardWay) ||
           evalInGlobalScope_fail;

    function test(f) {
        try {
            f(scr);
            if (typeof window[fname] === 'function') {
                return f;
            }
        }
        catch (e) {
            return false;
        }
        finally {
            try { delete window[fname]; } catch (e) { window[fname] = undefined; }
        }
    }
    function evalInGlobalScope_execScript(str) {
        window.execScript(str);
    }
    function evalInGlobalScope_windowEval(str) {
        window.eval(str);
    }
    function evalInGlobalScope_theHardWay(str) {
        var parent, script, d = document;

        parent = d.body || d.documentElement || d.getElementsByTagName('head')[0];
        if (parent) {
            script = d.createElement('script');
            script.appendChild(d.createTextNode(str));
            parent.appendChild(script);
        }
    }
    function evalInGlobalScope_fail() {
        throw "evalInGlobalScope: Unable to determine how to do global eval in this environment";
    }
})();

使用上述代码的实时示例


0

你不需要做很多改变,只需要一个小小的改动。

现在你有这样一行代码:

oDiv.innerHTML = foo;

只需将其更改为以下三行:

var oScript = document.createElement("script");
oScript.innerHTML = foo;
oDiv.appendChild(oScript);

并且让foo仅包含原始的JS代码, 而不包括<script></script>标签。

实时文本案例


在跨浏览器的情况下,设置 script 元素上的 innerHTML 不可靠。例如,在所有版本的 IE 中都会失败。因此,在我的答案中使用了各种机制来查找正确的 evalInGlobalScope 函数。 - T.J. Crowder
@T.J 它可以在最新版本的Chrome、Firefox和IE上运行。但是在IE9兼容模式下(据我所知,相当于IE8),确实会失败 - 你知道其他浏览器吗? - Shadow The Spring Wizard
@Shadow:IE9,IE8,IE7和IE6(已经死了!死了吧!)都失败了,但这没关系,因为它们提供了execScript。Firefox和其他一些浏览器提供了window.eval(与eval不同)。在几乎所有其他情况下,创建一个文本节点(而不是设置innerHTML)可以解决问题。再次参考我的答案中的evalInGlobalScope。它测试浏览器支持哪种机制(一次)。我在几年前做了大量研究。 - T.J. Crowder
好的,我只是希望有更简单的方法,但我猜你像往常一样是对的。 :) - Shadow The Spring Wizard

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