背景图全景展示

3

我有一个关于背景图片滚动的问题,它会无限重复。我的问题是它开始得很快,但很快就变得越来越慢(卡顿等)。以下是代码:

var panoramaTimeOutId = null;
var panoramaPosition = null;
$('.panorama-left').mousedown(function() {
    panoramaTimeOutId = setInterval(function(){
        panoramaMove(8, 1)
    }, 50);
}).bind('mouseup mouseleave', function() {
       clearInterval(panoramaTimeOutId);
});
$('.panorama-right').mousedown(function() {
    panoramaTimeOutId = setInterval(function(){
        panoramaMove(8, 2)
    }, 50);
}).bind('mouseup mouseleave', function() {
        clearInterval(panoramaTimeOutId);
});
function panoramaMove(amount, direction)
{
    var panorama = document.getElementsByClassName('panorama_foto')[0];
    if(panoramaPosition == null)
    {
        panoramaPosition = panorama.style.backgroundPosition;
        panoramaPosition = parseInt(panoramaPosition[0].replace("px",""));
    }
    if(direction == 1)
    {
        panoramaPosition = panoramaPosition + amount;
        panorama.style.backgroundPosition = panoramaPosition+"px";
    }
    else
    {
        panoramaPosition = panoramaPosition - amount;
        panorama.style.backgroundPosition = panoramaPosition+"px";
    }
}

我已经尝试了一些优化方法。比如使用标准的JavaScript编写函数。只在增量变量中包含一个简单的整数,计算panoramaPosition只进行一次。但它仍然会出现卡顿。
我还尝试更改间隔时间和像素数量,但在某些电脑上仍然会出现卡顿。例如,该网站是为平板电脑设计的,在平板电脑上会出现卡顿,而在我编程的电脑上不会。而且必须确保它在平板电脑上正常工作。
这是一个JSbin示例: http://jsbin.com/upociv/1/edit 希望有人能给出优化建议或普遍的建议,以提高其性能。
快速提醒:必须支持iPad(1/2/3),所有Galaxy平板电脑以及IE 8+ Firefox Chrome等浏览器。

请使用_CSS 3_完成此操作,不要使用_JavaScript_。相关MDN页面 - Paul S.
必须支持IE8及以上版本。因此,CSS3动画不是一个选择。对于网站的这个特定方面来说,也不是。 - N.Schipper
不要通过逐渐增加像素的数量来移动panoramaPosition,而是通过panoramaPosition %(图像宽度)来移动它。这可能会有所帮助。 - Blazemonger
我可以问一下在这个上下文中它确切的作用是什么吗?我的意思是,它不只是将图像移动剩余像素的除法吗? - N.Schipper
2个回答

2

不要将panoramaPosition按逐渐增加的像素移动,而是尝试通过panoramaPosition % (图像宽度)来移动。

这样,您就不必让浏览器试图在左边从10,000像素处开始无形地平铺背景图像——相反,它最多只需要平铺两次。 (您还将避免发生小但非零的整数溢出错误。)

if(direction == 1)
{
    panoramaPosition = panoramaPosition + amount;
    panorama.style.backgroundPosition = (panoramaPosition%1277)+"px";
}
else
{
    panoramaPosition = panoramaPosition - amount;
    panorama.style.backgroundPosition = (panoramaPosition%1277)+"px";
}

http://jsbin.com/upociv/2/edit

然而,如果您能够在CSS3中实现此功能,那么就应该这样做——Modernizr可以让您在JavaScript中检测浏览器是否支持CSS3过渡和变换。


1
刚在这两个平板电脑上试了一下,都没有问题 :) 非常感谢。我知道我应该把这个作为纯粹的后备选项。不过如果有时间,我会考虑一下的,因为整个项目都是基于短时间完成的,所以如果有时间,我会把它作为旧浏览器不支持动画的后备选项。(希望我能给你点赞 :< 我需要更多的积分才能做到,希望其他人可以给你点赞) - N.Schipper
很棒的解决方案。我认为模数运算符被许多程序员低估了。 - dev_row

1
自从我评论之后,我一直在尝试重新编写 jQuery 以避免使用它的大量开销,并尽可能地缓存。调用 Panorama 返回一个 Object,其中所有内容都整齐地放在属性中。前两个参数是必需的。
我为 addEventListener 做了一个兼容性处理,我称之为 listen,你可能也需要一个用于 getElementsByClassName演示代码
function Panorama(fullheight, fullwidth, foto, left, right) {
    var panorama = {};
    // crossbrowser listener
    function listen(node, ev, fn) {
        var a = ev.split(' '), i;
        if (node.addEventListener)
            for (i = 0; i < a.length; ++i)
                node.addEventListener(a[i], fn);
        else
            for (i = 0; i < a.length; ++i)
                node.attachEvent('on' + a[i], fn);
    }
    // short convert (px?) string to number, might be useful
    function Xpx(s) {
        return parseFloat(s.replace(/[^\d.]/, ''));
    }
    // movement
    function move(amount, direction) {
        if(direction) {
            panorama.position += amount;
            if (panorama.position > panorama.width)
                panorama.position %= panorama.width;
            foto.style.backgroundPosition = panorama.position + 'px';
        }
        else {
            panorama.position -= amount;
            if (panorama.position < 0)
                panorama.position = panorama.width - ((-panorama.position) % panorama.width);
            foto.style.backgroundPosition = panorama.position + 'px';
        }
    }
    function zoom(scale) {
        panorama.scale = scale;
        panorama.height = scale * fullheight;
        panorama.width = scale * fullwidth;
        foto.style.zoom = scale;
    }
    panorama.move = move;
    panorama.zoom = zoom;
    // cache nodes
    if (!foto) foto = document.getElementsByClassName('panorama_foto')[0];
    if (!left) left = document.getElementsByClassName('panorama-left')[0];
    if (!right) right = document.getElementsByClassName('panorama-right')[0];
    panorama.node = {
        foto: foto,
        left: left,
        right: right
    };
    // panorama scaled size info
    panorama.height = fullheight;
    panorama.width = fullwidth;
    panorama.scale = 1;
    // values
    panorama.timeout = null;
    panorama.position = 0;
    // left
    listen(left, 'mousedown', function() {
        panorama.timeout = setInterval(
            function(){ move(8, 1); },
            50
        );
    });
    listen(left, 'mouseup mouseout', function() { clearInterval(panorama.timeout); });
    // right
    listen(right, 'mousedown', function() {
        panorama.timeout = setInterval(
            function(){ move(8, 0); },
            50
        );
    });
    listen(right, 'mouseup mouseout', function() { clearInterval(panorama.timeout); });
    return panorama;
}

var pan = Panorama(414, 1277);

我已经离开工作岗位了(这也是为什么回复这么慢的原因),所以无法测试这个解决方案。但是我猜想,如果将此与上面的答案结合起来,由于它是纯JavaScript,结果会更好。明天我会尝试并合并这两个答案。另外,那个位置部分是一个聪明的改变,因为它在页面加载时始终为0。谢谢 :) - N.Schipper
如果你正在执行大量循环,比如数千次,那么使用纯JS而不是jQuery确实只有实际优势。即使如此,方便性通常会超过额外处理的毫秒数。 - Blazemonger
@Blazemonger 这个答案中最大的优化可能是缓存而不是移除 _jQuery_,没错。我只是尝试了我认为可能是优化的任何事情,即使它只是微小的优化,因为主要的想法毕竟是减少卡顿。 - Paul S.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接