0

我有一个 jQuery 函数,用于setInterval()慢慢输入一个短语——就像短语“string one”一样,每个字符都会在设定的毫秒数后打印到屏幕上。

问题是,在我的代码中,我一个接一个地对函数进行了两次调用,并且它们重叠,因为它似乎setInterval()不会停止正常的代码流。很难解释,这是我的 jsFiddle,它显示了会发生什么。

这是我的功能:

function type(text) {
    if(intv == null) {
        var textArray = text.split("");
        var length = textArray.length - 1;
        var i = 0;

        $("#div").append('<p class="text' + n + '"></p>' + "\n"); // creates a paragraph to print every character to (n is a global var)

        intv = setInterval(function() {
            if(i <= length) {
                var a = textArray[i];
                $('#div .text' + n).text($('#div .text' + n).text() + a); // appends the character to the paragraph created above
                i++;
            }
            else {
                alert("stopping interval..."); // just lets me know when the interval is stopping
                clearInterval(intv);
                intv = null;
                n++;
            }
        }, 60);
    }
    else {
        alert("the interval is not null"); // lets me know if the previous setInterval has stopped firing
    }
}

我是这样称呼它的:

type("string one");
type("string two");

问题是“弦一”和“弦二”最终同时触发,或者开始无限循环,或者只有第一个有效。

我真的不知道是否有办法解决这个问题,我的搜索没有任何结果。我不知道这是否是一个普遍的问题。有没有办法让第二根琴弦在第一根琴弦完成之前不触发?

提前谢谢。

4

2 回答 2

3

setInterval实际上只安排一个间隔每隔这么多毫秒运行一次。之后,一切仍然有效,因此您可以使用页面上的其他模块(如果您无法使用,那将毫无用处)。

如果您确实想等到间隔 #1 完成,您可以调用您传递的函数。就像是:

function type(text, functionIfDone) {
// ...
            clearInterval(intv);
            functionIfDone();  // call the function now because the interval is over

像这样使用它:

type("string one", function() {
    type("string two");
});

如果您不想使用回调,那么您可以使用一些处理排队的辅助函数:http: //jsfiddle.net/pZtje/

var currentInterval;
var intervals = [];

var startInterval = function(func, time) {
    intervals.push({
        func: func,
        time: time
    });
    checkQueue();
};

var checkQueue = function() {
    if(currentInterval == null) {
        var item = intervals.shift();
        if(item) {
            currentInterval = setInterval(item.func, item.time);
        }
    }
};

var stopInterval = function() {
    clearInterval(currentInterval);
    currentInterval = null;
    checkQueue();
};


// Usage:

var i = 0;
function foo() {
    console.log(i);
    i++;
    if(i === 3) {
        i = 0;
        stopInterval();
    }
}

startInterval(foo, 1000);
startInterval(foo, 1000);
于 2012-09-20T16:14:37.957 回答
2

看看这里:http: //jsfiddle.net/ymxu5/12/

首先,设置一个函数队列来跟踪我们的位置:

function Queue(){
    this._fns = [];
    this._args = [];
    this._running = false;
    var that = this;

    this.add = function(fn){
        console.log(fn.name + " added");
        that._fns.push(fn);
        var args = Array.prototype.slice.call(arguments, 1);
        that._args.push(args);

        if (!that._running)
            that.next();

        return that;
    },
    this.next = function(){        
        if (that._fns.length == 0){
            that._running = false;
        }
        else{
            that._running = true;
            that._fns.shift().apply(that, that._args.shift());
        }
    }
};

然后,您需要调整您的方法以使用queue.next();. 我已经设置了Queue对象来调用每个函数,改变了对象的上下文thisQueue这就是var queue = this;使用的原因。

function type(text){
    var queue = this;
    var $con = $("<p>").appendTo("#div");

    var typeText = function(con, txt, cursor){
        if (cursor < txt.length){
            con.text(con.text() + txt[cursor]);
            setTimeout(function(){
                typeText(con, txt, cursor + 1);
            }, 60);
        }
        else{
            setTimeout(function(){
                queue.next();
            }, 250);
        }
    };
    typeText($con, text.split(""), 0);
}

function flicker(sel){
    var queue = this;

    // note that this will cause issues if "sel" selects multiple things
    // because it will create multiple callbacks with jQuery, and `next` will
    // be called once for each item in "sel"
    $(sel).fadeOut("fast", function(){
        $(this).fadeIn("fast", function(){
            queue.next();
        });
    });
}

您将希望在Queue整个范围内都可以访问对象。我在这里使它成为全球性的:

var q = new Queue();
var senNum = 0;

$(function(){    
    $("#button").click(function(){
        q.add(type, "Sentence " + (++senNum)).add(flicker, "p:nth-child("+senNum+")");
    });        
});

我还冒昧地使该add方法可链接,因此您可以像上面一样使用它。​</p>

下面是一个使用一些方法来创建类似控制台的界面的示例:

http://jsfiddle.net/ymxu5/15/

于 2012-09-20T16:40:35.247 回答