尝试动态加载API和JS文件

时间:2011-11-20 03:51:41

标签: javascript jquery api

我正在尝试动态加载Skyscanner API,但它似乎不起作用。我尝试了一切可能的方式,一切都发生了,内容消失了。

我试过console.log但没有结果;我尝试了chrome的开发人员工具中的元素,虽然所有内容的css保持不变,但内容仍然消失(我认为它可能是在html / body类型上添加display:none)。我尝试了所有Google的异步技巧,但又是空白页。我尝试了所有用于异步加载的js插件,结果仍然相同。

Skyscanner的API文档很差,虽然它们提供回调但它不像google API的回调那样工作。

示例:http://jsfiddle.net/7TWYC/

在头部加载API的示例:http://jsfiddle.net/s2HkR/

那么如何在按钮点击或异步上加载api?没有文件在HEAD部分。如果有办法阻止document.write使页面空白或以任何其他方式。我不介意使用普通的js,jQuery或PHP。

编辑:

我已经将奖金设置为我以前50的上限。

Orlando Leite回答了关于如何使这个asynch api加载的非常接近的想法,虽然有些功能不起作用,例如选择日期,我无法设置样式。

我正在寻找一个答案,我将能够使用所有功能,以便它可以正常工作,如果它是在加载时加载。

以下是奥兰多的更新小提琴:http://jsfiddle.net/cxysA/12/

-

编辑2关于Gijs答案:

Gijs提到了覆盖document.write的两个链接。这听起来很棒,但我认为不可能实现我的目标。

我使用John的Resig方法来阻止document.write可以在这里找到:http://ejohn.org/blog/xhtml-documentwrite-and-adsense/

当我使用这种方法时,我成功加载了API,但是根本没有加载snippets.js文件。

小提琴:http://jsfiddle.net/9HX7N/

3 个答案:

答案 0 :(得分:5)

我相信你想要的是:

function loadSkyscanner()
{
    function loaded()
    {
        t.skyscanner.load('snippets', '1', {'nocss' : true});

        var snippet = new t.skyscanner.snippets.SearchPanelControl();
        snippet.setCurrency('GBP');
        snippet.setDeparture('uk');
        snippet.draw(document.getElementById('snippet_searchpanel'));
    }

    var t = document.getElementById('sky_loader').contentWindow;
    var head = t.document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.onreadystatechange= function() {
        if(this.readyState == 'complete') loaded();
    }
    script.onload= loaded;
    script.src= 'http://api.skyscanner.net/api.ashx?key=PUT_HERE_YOUR_SKYSCANNER_API_KEY';
    head.appendChild(script);
}

$("button").click(function(e)
{
    loadSkyscanner();
});

在iframe#sky_loader中加载skyscanner,在调用加载函数后创建SearchPanelControl。但最后,片段在主文档中绘制。这真的是一个奇怪的解决方法,但它确实有效。

唯一的限制是,你需要一个iframe。但您可以使用display:none隐藏它。

A working example

修改

抱歉,我没有看到。现在我们可以看到skyscanner API有多糟糕。它放置两个div来进行自动完成,但不是相对于你调用绘制的元素,而是文档。 在iframe中加载脚本时,document是iframe文档。

有一个解决方案,但我不建议,实际上是一种解决方法:

    function loadSkyscanner()
{
    var t;
    this.skyscanner;
    var iframe = $("<iframe id=\"sky_loader\" src=\"http://fiddle.jshell.net/orlleite/2TqDu/6/show/\"></iframe>");

    function realWorkaround()
    {
        var tbody = t.document.getElementsByTagName("body")[0];
        var body = document.getElementsByTagName("body")[0];

        while( tbody.children.length != 0 )
        {
            var temp = tbody.children[0];
            tbody.removeChild( temp );
            body.appendChild( temp );
        }
    }

    function snippetLoaded()
    {
        skyscanner = t.skyscanner;

        var snippet = new skyscanner.snippets.SearchPanelControl();
        snippet.setCurrency('GBP');
        snippet.setDeparture('uk');
        snippet.draw(document.getElementById('snippet_searchpanel'));

        setTimeout( realWorkaround, 2000 );
    }

    var loaded = function()
    {
        console.log( "loaded" );
        t = document.getElementById('sky_loader').contentWindow;

        t.onLoadSnippets( snippetLoaded );
    }

    $("body").append(iframe);
    iframe.load(loaded);
}

$("button").click(function(e)
{
    loadSkyscanner();
});

在加载代码段时,使用另一个加载和回调的html加载iframe。加载后,在设置超时后创建所需的片段,因为我们无法知道何时加载了SearchPanelControl。这个realWorkaround将自动完成div移动到主文档。

You can see a work example here

The iframe loaded is this

修改

修复了您找到的错误并更新了链接。

for循环已经消失并添加了一段时间,现在效果更好。

    while( tbody.children.length != 0 )
    {
        var temp = tbody.children[0];
        tbody.removeChild( temp );
        body.appendChild( temp );
    }

答案 1 :(得分:3)

skyrunner.js文件中,他们使用document.write使页面在加载回调时变为空白......所以这是你的场景中的一些后果..

  1. 当您点击按钮时,这会使页面空白。
  2. 所以,它会从页面中删除所有内容甚至'jQuery.js',这就是为什么回调无法正常工作...即无法调用main函数,因为这是使用jQuery编写的。
  3. 你错过了一个id = map的目标'div'标签(根据代码)。实际上这是地图加载的目标。
  4. 我观察到的另一件事是map在当前上下文中实际上不是div,即将api映射到load。
  5. 在这里你必须采用旧学校方法,那就是..你应该在头部内容的顶部包含你的skyrunner.js文件。

    所以尝试下载该文件并包含在head标签中。

    由于

答案 2 :(得分:3)

对于像这样的有问题的情况,您可以覆盖document.write。 Hacky是地狱,但它确实有效,你可以决定所有内容的去向。见例如。 this blogpost by John Resig。这忽略了IE,但是通过一些工作,这个技巧也适用于IE,参见例如。 this blogpost

因此,我建议使用您自己的函数覆盖document.write,在必要时批量输出,并将其放在您喜欢的位置(例如,在<body>底部的div中)。这应该可以防止脚本破坏您网页的内容。

编辑:好的,所以我花了一些时间来研究这个脚本。为了将来参考,请使用http://jsbeautifier.org/之类的内容来调查第三方脚本。这种方式更容易阅读。幸运的是,几乎没有任何混淆/缩小,所以你有他们的API文档的补充(我无法找到,顺便说一句 - 我只找到'代码向导',我没有兴趣)

这是一个几乎可以运作的例子:http://jsfiddle.net/a8q2s/1/

以下是我采取的步骤:

  1. 覆盖document.write。这需要在之前加载初始脚本。您的替换函数应将其代码字符串附加到DOM中。不要打电话给旧的document.write,这只会让你犯错误而且不会做你想做的事情。在这种情况下,您很幸运,因为所有内容都在一个document.write调用中(检查初始脚本的来源)。如果不是这种情况,那么你必须批量处理所有内容,直到他们给你的HTML有效和/或你确定没有其他内容出现。
  2. 使用jQuery的$.getScript或等效项单击按钮上的初始脚本。传递一个回调函数(为了清楚起见,我使用了一个命名的函数引用,但如果你愿意,可以内联它。)
  3. 告诉Skyscanner加载模块。
  4. 编辑#2:哈,他们有一个API(skyscanner.loadAndWait),用于在脚本加载后获得回调。使用它:

    http://jsfiddle.net/a8q2s/3/

    (注意:这似乎仍然在内部使用超时循环)