0

「stringone」というフレーズのように、フレーズをゆっくりと入力するために使用するjQuery関数がsetInterval()あります。各文字は、設定されたミリ秒数後に画面に出力されます。

問題は、私のコードでは、関数への2つの呼び出しが次々に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");

問題は、「文字列1」と「文字列2」の両方が同時に起動し、無限にループを開始するか、最初の1つだけが機能することです。

これを修正する方法があるかどうかは本当にわかりませんが、検索しても何も得られませんでした。これが一般的な問題かどうかはわかりません。最初のストリングが完了するまで、2番目のストリングが発火しないようにする方法はありますか?

よろしくお願いします。

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のコンテキストをオブジェクトに変更しましたthis。これがが使用されるQueue理由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 に答える