我有一个jQuery函数,使用setInterval()
来慢慢输入一个短语 - 就像短语“string one”一样,每个字符将在设定的毫秒数后打印到屏幕上。
问题在于,在我的代码中,我有一个接一个地调用函数,并且它们重叠,因为setInterval()
似乎没有停止正常的代码流。很难解释,here's my 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");
问题是“字符串一”和“字符串二”都同时触发,并且无论是开始无限循环还是只有第一个起作用。
我真的不知道是否有办法解决这个问题,我的搜索没有任何结果。我不知道这是否是一个常见问题。有没有办法可以保持第二个字符串不被触发直到第一个字符串完成?
提前致谢。
答案 0 :(得分: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);
答案 1 :(得分: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
方法可链接,所以你可以像上面一样使用它。
这是使用一些方法创建类似控制台的界面的示例: