【问题标题】:Trying to load an API and a JS file dynamically尝试动态加载 API 和 JS 文件
【发布时间】:2011-11-20 03:51:41
【问题描述】:

我正在尝试动态加载 Skyscanner API,但它似乎不起作用。我尝试了我能想到的所有可能的方法,结果所有的内容都消失了。

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

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

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

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

那么如何在按钮单击或异步时加载 api?没有文件在 HEAD 部分。如果有办法阻止 document.write 使页面变为空白或任何其他方式。我不介意使用纯 js、jQuery 或 PHP。

编辑:

我在之前的 50 个基础上设置了 250 个赏金。

Orlando Leite 回答了一个关于如何使这个异步 api 加载的非常接近的想法,尽管某些功能不起作用,例如选择日期并且我无法设置样式。

我正在寻找一个答案,我将能够使用它的所有功能,以便它像在加载时一样工作。

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

-

在 Gijs 上编辑 2 答案:

Gijs 提到了覆盖 document.write 的两个链接。这听起来是一个很棒的想法,但我认为这不可能完成我正在尝试的事情。

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

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

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

【问题讨论】:

  • 脚本似乎根据 API 密钥加载了另一个脚本。很奇怪,当我点击按钮时,它会清理body标签o.O
  • 我喜欢你的句柄是 jQuerybeast,你的代表是 666。你的工作已经完成了。
  • @thinkingstiff 通过了!对这个问题有任何线索吗?

标签: javascript jquery api


【解决方案1】:

我相信你想要的就是它:

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。但最后,sn -p 绘制在主文档中。这确实是一个奇怪的解决方法,但它确实有效。

唯一的限制是,您需要一个 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,该 html 在加载 sn-p 时加载和回调。加载后创建所需的 sn-p 并设置超时后,因为我们不知道 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 );
    }

【讨论】:

  • 这似乎是我一直在寻找的东西,尽管请注意自动完成功能不起作用?请在此处查看:jsfiddle.net/s2HkR 这是加载 API 的默认方式。请注意输入城市时搜索表单的自动完成功能。在您的工作示例中,它正在停止工作。你这样做的想法是天才,我不介意隐藏 iframe。谢谢
  • 太棒了。好吧,您不推荐,但我认为我没有其他解决方案,不是吗?它适用于仪表板 web 应用程序,当他们的服务器滞后时,所有仪表板都会滞后。
  • 好吧,我已经花了一个小时来解决这个问题。我认为这是我页面上的问题,但我只是发现它也不适用于您的示例。看看这个:jsfiddle.net/orlleite/cxysA/7/show 如果你自己查看你的小提琴,它不会显示任何东西。 (虽然可行:fiddle.jshell.net/orlleite/cxysA/7/show)再次感谢
  • 必须是同一个域名吗?它令人困惑。 jsfiddle.net/orlleite/cxysA/7/showfiddle.jshell.net/orlleite/cxysA/7/show 的源代码完全相同,但一个有效,另一个无效。就我而言,它们位于同一目录但文件不同
  • 我收到此错误:未捕获的类型错误:无法调用未定义加载的方法“onLoadSnippets”
【解决方案2】:

对于这种有问题的情况,您可以覆盖document.write。哈克,但它有效,你可以决定所有内容的去向。参见例如。 this blogpost by John Resig。这忽略了 IE,但是通过一些工作,这个技巧也可以在 IE 中使用,参见例如。 this blogpost.

所以,我建议用您自己的函数覆盖document.write,在必要时将输出批量化,然后将其放在您喜欢的位置(例如,在您的&lt;body&gt;' 底部的一个div 中)。这应该可以防止脚本破坏您的页面内容。

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

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

这是我采取的步骤:

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

编辑 #2:哈,他们有一个 API (skyscanner.loadAndWait) 用于在脚本加载后获取回调。使用该方法:

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

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

【讨论】:

  • 我正在尝试解决这个问题。说真的,如果我能弄清楚我会是最幸福的人。
  • 我相信这是不可能的。您必须加载 api,然后加载 sn-p,然后设置回调。如果您在 sn-p 之前停止 document.write,则不会加载 sn-p。反之亦然,如果您先加载 sn-p,则页面变为空白。检查我的小提琴:jsfiddle.net/bLmer
  • 基本上我正在寻找一种允许新 document.write 但阻止清除页面的方法。
  • 好的,我添加了一个工作示例。看起来还没有那么热,但我想那是因为你的 CSS 还没有应用?另外,到目前为止,我只在 Chrome 中进行了测试。 YMMV 在其他浏览器中,不提供也不暗示保证,yada yada。
  • 我用美化器浏览了他们的脚本。我是一个页面加载性能上瘾者,因此我有这个问题。现在等待您的答复,先生,我真的不知道如何感谢您。一个多月以来,我一直在思考如何解决这个问题。我尝试了所有我能想到的能力。非常感谢!
【解决方案3】:

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

  1. 当您单击按钮时,这会使页面变为空白。
  2. 因此,它会从页面中删除所有内容,甚至是“jQuery.js”,这就是为什么回调不起作用的原因。即无法调用主函数,因为这是使用 jQuery 编写的。
  3. 并且您错过了一个 id = map 的目标“div”标签(根据代码)。实际上这是地图加载的目标。
  4. 我观察到的另一件事是地图实际上不是当前上下文中的 div,即要加载的地图 api。

这里你必须使用老派的方法,也就是说..你应该在头部内容的顶部包含你的 skyrunner.js 文件。

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

谢谢

【讨论】:

  • 我注意到了。我的问题是不要在头部使用 skyscanner.js,因为有时它会滞后,导致我的整个 web 应用程序滞后。
  • 地球上有什么方法(PHP、AJAX)可以在点击按钮时加载它吗?有什么可以说的,取消所有document.write页面空白?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-26
  • 2010-10-17
  • 1970-01-01
  • 2019-03-12
  • 1970-01-01
相关资源
最近更新 更多