这个函数的递归有什么问题? (setTimeout问题)

发布于 2024-09-27 18:29:12 字数 2446 浏览 9 评论 0原文

我正在编写一个选取框脚本,因为我不喜欢这样的事实:对于大多数选取框脚本,当选取框到达最后一个项目时(考虑使用 ul,所以最后一个项目是最后一个 li),它会等到该项目离开屏幕,并且然后重置 ul 的位置,并开始在 agian 上滚动。

我的方法是创建 ul 的克隆,将其附加在当前 ul 之后,并开始滚动,然后在原始 ul 完全隐藏后将其删除。

除了一件事之外,这几乎是完美的。当您调用该函数时,它会生成 setTimout 所需的时间。此 setTimout 用于创建新的 UL 并设置其移动。

这对于第一个循环来说效果很好,但随后就会出现故障。

这有点难以解释,但似乎第二次应该调用超时,而不是等待时间,而是立即调用自己。请参阅 http://webspirited.com/marquee.html 获取示例

工作示例。 JavaScript代码如下:

var count = 0;
$('document').ready(function () {
    //generate some random rows
    for (var i = 0; i <= 20; i++)
    $('.ulscroll').append('<li>Content ' + i + '</li>');
    //add one row so we can see its the last
    $('.ulscroll').append('<li>Last Item</li>');

    //set the ul's width
    var width = 0;
    $('.ulscroll').children('li').each(function () {
        width += $(this).outerWidth();
    });
    log('ul width: ' + width);
    $('.ulscroll').width(width);

    //activate the marquee              
    marquee('.ulscroll', 1, false);
});

function marquee(id, speed, sub) {
    //next two lines debugging purposes only
    count += 1;
    log('Marquee ran ' + count + ' times');

    //store copy of speed sent it(to pass for recursion)
    var s1 = speed;
    //set speed to 10*
    speed = speed * 10;

    //store parent width, and own width (if sub then add on width of parent div)
    var pwidth = $(id).parent('div').outerWidth();
    var width = (sub ? $(id).width() + pwidth : $(id).width());

    //set timeout
    var t = (width - pwidth) * speed;
    setTimeout(function () {
        var clone = $(id).clone().css('left', pwidth);
        $(id).addClass('oldul');
        $(id).after(clone);
        marquee(id + ':not(.oldul)', s1, true);
    }, t);

    $(id).animate({
        left: '-=' + width
    }, width * speed, 'linear', function () {
        $(this).remove();
    });
}

function log(text) {
    $('#log').append('<div>' + text + '</div>');
}


Solution
The issue was caused by passing the selector in with :not(.ulold); Here is the revised setTimeout

setTimeout(function(){
  var clone = $(id).clone().css('left', pwidth);
  $(id).addClass('oldul');
  var idx = id.split(':');
  idx = idx[0];
  log('idx: '+idx);
  $(idx).after(clone);
  marquee(idx+':not(.oldul)', s1, true);
},t);

I am writing a marquee script because I do not like the fact that with most marquee scripts when the marquee reaches the last item (thinking using a ul, so last item is the last li), it waits till that item is off screen, and then resets the position of the ul, and starts the scrolling all over agian.

My approach is to create a clone of the ul, append it after the current ul, and start it scrolling, then delete the original ul once it is completely hidden.

This works almost perfect except for one thing. When you call the function it generates the time required for a setTimout. This setTimout is used to create the new UL and set it moving.

This works fine for the first loop, but then glitches up.

It is a bit hard to explain, but it seems to on the second time the timeout should be called, instead of waiting for the time, it just calls itself instantly. Please see http://webspirited.com/marquee.html for an example

For a working example. The javascript code is as follows:

var count = 0;
$('document').ready(function () {
    //generate some random rows
    for (var i = 0; i <= 20; i++)
    $('.ulscroll').append('<li>Content ' + i + '</li>');
    //add one row so we can see its the last
    $('.ulscroll').append('<li>Last Item</li>');

    //set the ul's width
    var width = 0;
    $('.ulscroll').children('li').each(function () {
        width += $(this).outerWidth();
    });
    log('ul width: ' + width);
    $('.ulscroll').width(width);

    //activate the marquee              
    marquee('.ulscroll', 1, false);
});

function marquee(id, speed, sub) {
    //next two lines debugging purposes only
    count += 1;
    log('Marquee ran ' + count + ' times');

    //store copy of speed sent it(to pass for recursion)
    var s1 = speed;
    //set speed to 10*
    speed = speed * 10;

    //store parent width, and own width (if sub then add on width of parent div)
    var pwidth = $(id).parent('div').outerWidth();
    var width = (sub ? $(id).width() + pwidth : $(id).width());

    //set timeout
    var t = (width - pwidth) * speed;
    setTimeout(function () {
        var clone = $(id).clone().css('left', pwidth);
        $(id).addClass('oldul');
        $(id).after(clone);
        marquee(id + ':not(.oldul)', s1, true);
    }, t);

    $(id).animate({
        left: '-=' + width
    }, width * speed, 'linear', function () {
        $(this).remove();
    });
}

function log(text) {
    $('#log').append('<div>' + text + '</div>');
}


Solution
The issue was caused by passing the selector in with :not(.ulold);
Here is the revised setTimeout

setTimeout(function(){
  var clone = $(id).clone().css('left', pwidth);
  $(id).addClass('oldul');
  var idx = id.split(':');
  idx = idx[0];
  log('idx: '+idx);
  $(idx).after(clone);
  marquee(idx+':not(.oldul)', s1, true);
},t);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

煮酒 2024-10-04 18:29:12

问题很可能出在这段代码上。

    var clone = $(id).clone().css('left', pwidth);
    $(id).addClass('oldul');

您重复使用选择器的事实会把事情搞砸,因为随着时间的推移,原始选择器会匹配很多东西。

在初始调用中使用 marquee(' .ulscroll:not(.oldul)', 1, false);

The problem, most likely, lies with this code..

    var clone = $(id).clone().css('left', pwidth);
    $(id).addClass('oldul');

The fact that you are re-using the selector messes things up because the original selector matches a lot of things as time progresses..

In the initial call use marquee('.ulscroll:not(.oldul)', 1, false);

审判长 2024-10-04 18:29:12

学习使用好的调试器,例如 Firebug。您将看到最终动画结束回调(删除与选择器匹配的元素的回调)在匿名超时函数(调用 marquee 的回调)之前被调用。

示例页面上的代码存在问题(但不在发布的代码中):tout 对于每次调用 marquee 都是本地的。 clearTimeout(tout) 调用不执行任何操作。

最后,请不要使用字幕。它存在可用性问题:移动文本更难阅读、会分散注意力,并且总是会移动对某些读者来说要么太快,要么对某些读者太慢。

Learn to use a good debugger, such as Firebug. You'll see that eventually the animation end callback (the one that removes the elements matching the selector) gets called before the anonymous timeout function (the one that calls marquee).

An issue with the code on the sample page (but not in the posted code): tout is local to each invocation of marquee. The clearTimeout(tout) call does nothing.

Lastly, please don't use a marquee. It has usability problems: moving text is harder to read, causes distraction, and will always move either too quickly for some readers or too slowly for some readers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文