如何让浏览器 运行 javascript 代码被 dom 操纵注入?

How to make the browser run javascript code injected by dom manipulation?

我想提供一些其他页面可以包含的 html 片段。

html 内容看起来像这样:

<div id="coolIncludable" style="display:none"> <!--be invisible until you are finished initializing -->
   <div>Cool stuff here</div>
   <div>More cool stuff and so on...</div>
</div>
<script src="http://somehwere/jquery.js"></script>
<script src="http://somewhere/something.js"></script>
<script>
    $(function(){$('#coolIncludable').show();});//<- actually contained in a script file, just for illustration
</script>

我打算使用此处详述的方法:https://www.w3schools.com/howto/howto_html_include.asp 进行实际的包含。假设页面看起来像这样:

<html>
    <head>
    </head>
    <body>
        <H1>Content before snippet</H1>
        <div id="registerWrapper" html-include="http://somehwere/snippet.html">
            No content loaded
        </div>
        <H1>Content after snippet</H1>
        <script type="text/javascript" src="http://somehwere/html-include.js"></script>
    </body>
</html>

html 代码片段可以正常加载和嵌入,但它附带的 javascript 永远不会执行。有没有办法嵌入内容,包括确保它们被执行的脚本?

更新 我应该明确表示我不希望控制嵌入页面,所以我不能依赖它加载 jQuery 或任何其他内容。因此,我避免在嵌入函数中使用 jQuery,并将自己限制为普通的 Javascript。加载 jQuery 是代码段末尾的标签会做的事情之一。

由于您使用的是 jQuery,因此您可以使用它内置的 load() 方法来执行您想要的操作

类似于:

HTML

<div class="include" data-include="page2.html"></div>

JS

$('.include').each(function(){
     const $el = $(this), url = $el.data('include');
     $el.load(url)
});

然后确保新内容的脚本标签在该内容下方。

Simple working demo

回想起来,我的错误是显而易见的:

$(function(){$('#coolIncludable').show();});是什么意思 做?它执行$('#coolIncludable').show();吗?不,它没有。它注册了一个 回调 来执行此操作,以便由 'load' 事件触发,该事件已经触发,并且不会再次触发。

另一方面,这确实是一个有争议的问题,因为代码甚至从未执行过。

以下是我对 javascript

动态加载的了解

直接注入脚本标签不起作用

  • 通过设置 element.innerHtml 注入的脚本标签执行
<div id="snippet">
    ...
</div>
<!-- neither of these will be executed -->
<script type="text/javascript">alert("stuff");</script> 
<script type="text/javascript" src="http://somewhere/script.js"></script>

动态创建脚本标签确实有效

有效的是按照本文所述的方式生成动态标签:JavaScript Madness: Dynamic Script Loading

var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.src= 'helper.js';
head.appendChild(script);
//At this point (or soon after) the code in helper.js will be executed

您可以在加载脚本中执行此操作。我的加载脚本看起来像这样:

function importJsFiles(){
    const scriptFiles = ["http://somewhere/jquery.js",
                         "http://somewhere/stuff.js",
                         "http://somewhere/bootstrapSnippet.js"];
    for (let i = 0; i< scriptFiles.length; i++){
        importJsFile(scriptFiles[i]);
    }
}

function includeSnippet(){
    //See https://www.w3schools.com/howto/howto_html_include.asp
    //We still have to do it without jQuery, 
    //because at the time this executes the injected jquery.js 
    //hasn't run and we do not yet have jQuery available
}



importJsFiles();
//At this point, all script tags are created, but the scripts are NOT loaded yet
includeSnippet();
//At this point, the dom is in its final shape
bootstrapSnippet(); //<- This won't work, because the script tags injected by this code won't be evaluated until after this file/function/whatever returns

//bootstrapSnippet.js
function bootstrapSnippet(){
    alert("Snippet JS running")
    if (window.jQuery) {
            
            alert("JQuery is avaliable"); //<- This will fire, because the new script 
                            // tags are evaluated in order, and we put the
                            // jquery.js one before the bootstrapSnippet.js one
        }

        //So now we CAN do this:
        $('#coolIncludable').show(); 
}

bootstrapSnippet();

this post 中有许多更有趣的想法和细节,我从上面的 link 中挑选出来。我希望有一天我能抽出时间来探索它们。