jQuery加载并不像我预期的那样工作

时间:2012-04-01 12:44:24

标签: jquery

$(".content")
        .load("content/intro.html #bt")
        .hide()
        .fadeIn(2000)
        .delay(2000)
        .fadeOut(2000)
        .load("content/intro.html #ofm")
        .fadeIn(2000)
        .fadeOut(2000)
        .load("content/main.html")
        .fadeIn(800);

我希望jQuery首先加载内容(intro.html #bt等)但它实际上会加载main.html而不会执行列表中的其他内容。在这种情况下,三次淡出。什么是变通方法?

2 个答案:

答案 0 :(得分:4)

这可能是违反直觉的,但在理解jQuery的工作方式时会很有意义。

您呼叫的所有方法都是在同一时间开始的。所以它加载所有三个html页面,但你的眼睛只看到最后一个,然后你看到动画启动。你需要告诉jQuery等待每个命令完成后再执行下一个。

(你正在做什么被称为 chaining ,虽然它是quite useful,但它并不像你想要的那样工作,而且这不是你需要的。)

通过使用回调或deferred pattern,执行流程可以是控制器。 jQuery实现了两者(我认为仅在v1.5之后延迟)但load()只实现了回调。

基本上,你告诉jQuery要加载东西并运行动画,但你告诉它等待上一个命令完成后再继续。

这是达到你想要的一种方式。我没有测试它,但它证明了原理。

$(".content")
    .load("content/intro.html #bt", function() {
        $(this).hide().fadeIn(2000, function() {
            $(this).fadeOut(2000, function(){
                $(this).load("content/intro.html #ofm", function() {
                    $(this).fadeIn(2000, function() {
                        $(this).fadeOut(2000, function() {
                            $(this).load("content/main.html", function(){
                                $(this).fadeIn(800);
                            });
                        });
                    });
                });
            });
        });
    });

注意每个方法如何回调?这样,您就知道在继续之前已完成上一个方法的执行。

注意,这段代码远非理想!有更好的方法可以使用deferred模式和the many jQuery pulse plugins之一来实现此模式。

一旦你理解了为什么jQuery以这种方式工作,请查看Paul irish's post on how to address the ugly syntax this creates

您可能还需要签出TameJS,它会在javascript中添加一个名为await的构造,以简化此类代码。

答案 1 :(得分:0)

加上我的两分钱:

可以用帮助器链接这些东西(在某种程度上)。我一直希望能够将动画和负载链接在一起,所以在阅读了你的问题之后,最后决定深入挖掘并最终弄清楚如何将这些东西链接起来,这就是我想出来的。

function Resolver () {
    this.itemsToResolve = [];
    this.context = {};  
    //this.context is only needed if you want to pass 
    //something to the next anonymous function
    this.next = function(){ 
        var def = $.Deferred();
        def.then.apply(def,arguments);
        this.itemsToResolve.push(def);
        return this;
    };
    this.resolveNext = $.proxy(function(){
        var p = this.itemsToResolve.shift();
        if (p){
            p.resolve(this);
        }           
    }, this);
 };

严格地说,我可能甚至不需要使用jQuery的延迟(s),但我正在努力研究可以充分利用它们的东西 - 如果这有任何意义,我不确定这对我有意义!

使用该帮助程序,这里修改了您的代码以使用它:

 var $c = $(".content");
 var res = new Resolver();
 res.next(function(r){
    $c.load("content/intro.html #bt",r.resolveNext);
 }).next(function(r){
    $c.hide()
    .fadeIn(2000)
    .delay(2000)
    .fadeOut(2000,r.resolveNext);
 }).next(function(r){
    $c.load("content/intro.html #ofm",r.resolveNext);    
 }).next(function(r){
    $c.fadeIn(2000)
    .fadeOut(2000, r.resolveNext);
 }).next(function(r){
    $c.load("content/main.html",r.resolveNext);  
 }).next(function(r){
    $c.fadeIn(800, r.resolveNext);
 });
 //and then finally, to start it off
 res.resolveNext();

可能有更精致的方法来做到这一点,但除此之外,我对它很满意。