我该如何有效地在$(document).ready()中使用yepnope.js?

15

我一直在实现yepnope脚本加载器,作为modernizr.js库的一部分。我已经成功地使jQuery加载和加载jQuery依赖项的脚本。我对异步加载资源比较陌生,所以这对我来说有点新颖。我一直在搜索,但以下内容并没有得到很多帮助。

我的问题是,在使用yepnope.js框架时,您认为如何有效地替换$(document). ready()函数的功能。

我的理论是,在我的基础库中创建一个合适命名的函数,然后将该变量设置为匿名函数,其中包含我现有的$(document).ready()代码。在所有脚本都在完成回调函数中加载之后,yepnope将调用该变量。

您是否同意这是一个好方法,或者我完全错误地处理了它?

(对于那些不知道的人,yepnope.js的异步性质意味着文档在yepnope加载程序完成之前调用$或jQuery,从而引发“$未定义”错误 <- 如果这是错误的,请纠正我。)

第一个问题,希望这是个好问题。


只是想澄清一下,我正在将它集成到一个已有很多现有js文件的网站中,这些文件适用于各个页面,并且依赖于document.ready()。也许这样做是错误的 - 我想听听你们所有人的意见。 - Ash Clarke
5个回答

11

如果在没有使用yepnope的情况下加载jQuery不是问题,那么有一种更简单的方法可以实现。

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>

<script>
    $.holdReady(true);

    yepnope.load({
        load: [
            'placeholder.js',
            'jquery-ui.min.js'
        ],
        complete: function (){
            $.holdReady(false);
        }
    });
</script>

谢谢!我不知道jQuery有这个功能。这个解决方案更简单、更优雅。 - Andrew Ensley
我应该把$(document).ready();放在这下面吗?它需要在自己的<script>标签中吗? - KJW
你应该将 $(document).ready() 放在单独的 <script> 标签中,在 $.holdReady() 之后。 - Damax

11

这是我使用的技巧。它使我可以在任何地方添加类似于 $(document).ready() 的调用。使用这种方法,您可以采用已经使用 jQuery 并具有现有 $(document).ready() 调用的站点,并轻松地将 yepnope 进行适配。

首先,在任何调用 $(document).ready() 的 javascript 之前,在文档头中添加此行 JS:

<script>
    var docready=[],$=function(o){function r(fn){docready.push(fn);}if(typeof o === 'function') r(o);return{ready: r}};
</script>

然后,将您的yepnope jQuery测试对象设置为类似于以下内容:

yepnope({
    load: '//ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js',
    complete: function() {
        $ = jQuery;         
        for(n in docready) $(document).ready(docready[n]);
    }
});

在jQuery加载之前,我们创建一个假的$(document).ready()。它将每个$(document).ready()调用存储在一个数组docready中。然后,一旦jQuery加载完成,我们使用现在已经加载的真正的jQuery对象覆盖我们的临时$对象。然后,我们遍历所有存储的$(document).ready()调用,并真正地执行它们。

更新:Chris Jones改进了这个版本,还包括对$(function() {})格式调用的覆盖。


嗨,我使用了你描述的方法,在关闭body标签之前放置了yepnope,一切都运行良好。但是:我在其他地方加载了jquery.min.js,所以使用这种方法会再次加载不必要的jquery吗?问候Andrea - cwhisperer
嗨,Andrea - 如果您已经尝试过预先加载jQuery,则可以执行以下操作: 1)从yepnope中删除加载jquery的调用,只留下其他脚本, 2)将加载jQuery的yepnope块更改为: { test: typeof jQuery == 'undefined', yep: '//ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js', complete: function() { $ = jQuery;
for(n in docready) $(document).ready(docready[n]); } } 3)删除早期同步加载的jQuery,并将使用jQuery的任何调用包装在$(document).ready(function() { ... })块中。
- Sc0ttyD
1
不错的解决方案。我一定也会尝试一下。但是,在这种情况下,如何处理通过JQuery.fn或$.fn注册的JQuery插件呢?我认为后者是最糟糕的,因为这些注册将成功并在之后被覆盖;)...或者我在插件方面漏掉了一些重要的点,使它们仍然像预期的那样工作吗? - DotBert

1
   <script type="text/javascript" src="/my-yepnope-stuff.js"></script>
</body>

在关闭 body 标签之前,您可以非常确定处于 $(document).ready() 状态。

您需要自己回答的问题是是否有意义强制 yepnope 以 $(document).ready() 方式加载,因为它的主要目的是打破首先脚本标记同步加载顺序。


我的问题是,在某些情况下,我必须测试文档是否准备就绪,因为我使用第三方控件库(telerik)。如果找不到控件(即尚未加载),它们的函数将返回null。除此之外,我希望朝着异步脚本加载的方向努力。 - Ash Clarke

0

我认为Alex Sexton的solution是正确的:

yepnope({
    load: '//ajax.googleapisOFFLINE.com/ajaxX/libs/jquery/1.7.1/jquery.min.js',
    callback: function () {
        if (!window.jQuery) {
            yepnope('/js/jquery-1.7.1.min.js');
        }
    },
    complete: function () {
      $(function(){
        $("div.whatever").css("color","red");
      });
    }
});

0

在@ezmilhouse的指导下,我考虑了实现我想要的最佳方式,同时仍保持与我们旧代码的兼容性。

我的解决方案是设置我的yepnope脚本加载器以分层方式加载所有必要的脚本,基于它们各自的依赖关系。一旦所有脚本都加载完成,您可以使用我的yepnope调用的complete属性来调用我的ready函数。这意味着文档已经准备好了,代码将没有任何问题。

我还将我的js移动到页面底部(这是我很久以前就应该做的事情,但我们有很多遗留页面! :))

这里是一个示例(仅使用错误的库/脚本名称进行说明):

yepnope({
    test: baseLib.debug,
    yep: { "max": "/version2/res/jquery/jquery-1.5.2.js" },
    nope: { "min": "/version2/res/jquery/jquery-1.5.2.min.js" },
    callback: {
        "max": function (url, result, key) {
            baseLib.Log("jQuery full loaded.");
        },
        "min": function (url, result, key) {
            baseLib.Log("jQuery min loaded.");
        }
    },
    complete: function () {
        if (window.$) {
            yepnope({
                test: base.debug,
                yep: {
                   "anotherscript": "script/url/here.js",
                   "anotherscript2": "script/url/here2.js"
                },
                nope: {
                    "anotherscript": "script/url/here-min.js",
                    "anotherscript2": "script/url/here2-min.js"
                },
                both: {
                    "anotherscript3": "script/url/here3.js"
                },
                callback: {
                    "anotherscript": function (url, result, key) {
                        baseLib.Log("anotherscript " + (result ? "Max" : "Min") + " loaded.");

                    },
                    "anotherscript2": function (url, result, key) {
                        baseLib.Log("anotherscript2 " + (result ? "Max" : "Min") + " loaded.");
                    },
                    "anotherscript3": function (url, result, key) {
                        baseLib.Log("anotherscript3 loaded.");
                    }
                },
                complete: function () {
                    baseLib.Log("Scripts Loaded");
                    baseLib.Page.Ready();
                }
            });

        }
        else {
            baseLib.Log("Could not load jQuery. No further jQuery dependent files loaded.", "error");
        }
    }
});

在我的页面js中,我将把一个函数赋值给baseLib.Page.Ready,然后由yepnope在完成时调用。

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