无法将脚本加载到iframe

时间:2017-02-10 12:38:10

标签: javascript html iframe

测试页: https://jsfiddle.net/y25rk55w/

在此测试页上,您可以看到3个<iframe>相互嵌入。每个<iframe>在其<script>标记中都包含<head>个标记。

问题是:浏览器只会加载第一个<script>中的<iframe>。其他两个<script>标签将出现在dom中,但浏览器甚至不会尝试加载它们。问题不是浏览器特定的,它可以在chrome,firefox中重新生成,即。在附加脚本之前添加超时或等待无法解决问题。所有iframe都有编程生成的内容似乎很重要;如果你用iframe用实际的src链接替换这个iframe,问题就会消失。

问题是:如何将脚本实际加载到iframes 2和3中?

完整的测试代码:

// It doesn't matter if the scripts exist or not
// Browser won't try to load them either way
var scripts = [
    '//testdomain.test/script1.js',
    '//testdomain.test/script2.js',
    '//testdomain.test/script3.js'
];

function createIFrame(win, onCreated) {
    var iframe = win.document.createElement('iframe');
    iframe.onload = function () {
        onCreated(iframe);
    };
    win.document.body.appendChild(iframe);
}

function loadScript(win, url) {
    var script = win.document.createElement('script');
    script.src = url;
    script.onload = function() {
        console.log("Script " + url + " is loaded.");
    };
    win.document.getElementsByTagName('head')[0].appendChild(script);
}

createIFrame(window, function(iframe1) {
    loadScript(iframe1.contentWindow, scripts[0]);
    createIFrame(iframe1.contentWindow, function (iframe2) {
        loadScript(iframe2.contentWindow, scripts[1]);
        createIFrame(iframe2.contentWindow, function (iframe3) {
            loadScript(iframe3.contentWindow, scripts[2]);
        });
    });
});

3 个答案:

答案 0 :(得分:1)

您的代码运行正常 - &gt; http://plnkr.co/edit/vQGsyD7JxZiDlg6EZvK4?p=preview

确保您在window.onloadDOMContentLoaded上执行createIFrame。

var scripts = [
    'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.js',
    'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.2/jquery.js',
    'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js'
];

function createIFrame(win, onCreated) {
    var iframe = win.document.createElement('iframe');
    iframe.onload = function () {
        onCreated(iframe);
    };
    win.document.body.appendChild(iframe);
}

function loadScript(win, url) {
    var script = win.document.createElement('script');
    script.src = url;
    script.onload = function() {
        console.log("Script " + url + " is loaded.");
    };
    win.document.getElementsByTagName('head')[0].appendChild(script);
}
window.onload = function(){
createIFrame(window, function(iframe1) {
    loadScript(iframe1.contentWindow, scripts[0]);
    createIFrame(iframe1.contentWindow, function (iframe2) {
        loadScript(iframe2.contentWindow, scripts[1]);
        createIFrame(iframe2.contentWindow, function (iframe3) {
            loadScript(iframe3.contentWindow, scripts[2]);
        });
    });
});
};

答案 1 :(得分:1)

在这个问题中你可以看到我正在省略协议:

/* This is valid to omit the http:/https: protocol.
   In that case, browser should automatically append 
   protocol used by the parent page */
var scripts = [
    '//testdomain.test/script1.js',
    '//testdomain.test/script2.js',
    '//testdomain.test/script3.js'
];

事情是,以编程方式创建的iframe具有协议about:(或javascript:,具体取决于您创建它们的方式)。我仍然无法解释为什么第一个脚本正在加载或为什么其他两个脚本根本没有出现在网络选项卡中,但我想这不是很重要。

解决方案:显式使用https://或以编程方式附加协议,使用类似下面的代码:

function appendSchema(win, url) {
    if (url.startsWith('//')) {
        var protocol = 'https:';
        try {
            var wPrev = undefined;
            var wCur = win;
            while (wPrev != wCur) {
                console.log(wCur.location.protocol);
                if (wCur.location.protocol.startsWith("http")) {
                    protocol = wCur.location.protocol;
                    break;
                }
                wPrev = wCur;
                wCur = wCur.parent;
            }
        } catch (e) {
            /* We cannot get protocol of a cross-site iframe.
             * So in case we are inside cross-site iframe, and
             * there are no http/https iframes before it,
             * we will just use https: */
        }
        return protocol + url;
    }
    return url;
}

答案 2 :(得分:0)

我使用比self-answer中提出的OP更简单的方法成功了。我使用以下方式生成URL:

$("#myInputID").blur(); 

其中new URL(scriptURL, window.location.href).toString(); 是需要修复以获取正确协议的网址,scriptURL是保存脚本的window元素的 。这可以处理与OP示例URL不同的场景:例如相对URL(iframe)或不以主机(../foo.js开头)的绝对URL。在我的情况下,上面的代码就足够了。

如果我要通过OP使用的窗口层次复制搜索,我可能会执行以下操作。这是TypeScript代码。删除类型注释以获得纯JavaScript。

/foo.js

如果窗口链产生非常有用的话,我没有默认的返回值,因为这表明比生成URL的问题要大得多。我的设置中的其他地方有问题。