New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

简单的图片轮播,多多的优化 #3

Open
ericdum opened this Issue Oct 31, 2013 · 1 comment

Comments

Projects
None yet
2 participants
@ericdum
Owner

ericdum commented Oct 31, 2013

今天分享一个很常见的东西——图片轮播。

虽然说这是一个很常见的东西,但真要论起来,其实有很多地方可以优化。

比如淘宝首页的图片轮播,如果一个顾客的鼠标像我这样傻逼得晃过去晃过来,被他经过的轮播就“停止”了。

注意鼠标移动的轨迹和轮播的大图片,如果用户在轮播周期内反复_经过_轮播元素,图片轮播就会“永远”停止。而下方的图片已经经过了几次轮播了。

xd_marque41

而同样的事情如果发生在心动游戏的官网上会,这不会有任何不符合预期的行为发生,鼠标悬停轮播停止,鼠标离开不影响轮播进程。

注意鼠标移动的轨迹和轮播的大图片

xd_marque31

引题结束,希望能引起你的兴趣,如若不然你应该不会看到这行字。。。或者下行字。。。

这个是我12年刚进入心动时写的,需求很简单——图片轮播、右下角链接。

为了实现这个需求,代码也可以很简单:

  1. 定义$.fn.xdMarquee,写成jquery扩展
  2. 函数中下载图片,并插入DOM
  3. 定义start、next、clear来控制轮播
  4. 定义右下角指示器click事件
  5. 开始轮播

源代码:

https://github.com/ericdum/mujiang.info/blob/master/share/marquee.js

捡重要的代码看:

    function marquee(data, options){
        //设置、初始化....
        //第二、三步
        var the = this;
        //第四步
        this.controller.find('span').live('click', function(){ 
            the.start(0, $(this).index()); 
        });
        //第五步
        this.start();
    }

    function start( timeout, index ) {
        this.clear(); //清除timeout
        this.promise(timeout, index);
    }

    function next(index) {
        // 执行动画 ....
        this.current = index;
        this.promise();//设置下次轮播
    }

    function promise( timeout, index ){
        timeout = timeout>=0 ? timeout : this.timeout;
        var the = this;
        this.tm = window.setTimeout(function(){
            the.next(index);
        }, timeout);
    }

    function clear() {
        window.clearTimeout(this.tm);
    }

悬停问题

因为我们认为用户鼠标悬停代表用户对图片产生了关注,所以悬停要暂停图片播放,就需要在上面初始化的方法中时候加入:

    this.hovering  = false;
    $(this).hover(function(){ 
        the.hovering = true; 
    }, function(){ 
        the.hovering = false; 
        the.start(); 
    });

然后再next方法中加入:

    if( this.hovering ) return;

这就可以了(另外要做好点击切换时的处理)。完成以后便发现了文章一开头提到的问题。

为了解决这个问题,首先想到的是在鼠标移走之后让图片立即改变。代码很简单,把上面第二段代码hover中对start的调用改成the.start(500)就好了——鼠标离开后500毫秒变换图片。

    //hover(function(){...},function(){...
    the.start(500)

但这就随之而来了另一个问题,如果用户老是经过这个地方,图片岂不是会不停地换——频率太快。

解决方案是如果图片播放的时间不足,则鼠标悬停对轮播不造成影响。实现的方法就是新增一个stopping状态。在next函数中判断hovering==true时,把它设置成true。而后在hover的第二个函数中判断:

    $(this).hover(function(){ 
        the.hovering = true; 
    }, function(){ 
        the.hovering = false; 
        if( the.stopping ){
            the.stopping = false;
            the.start(500); 
        }
    });

    //in next function
    if( this.hovering ) {
        this.stopping = true;
        return;
    }

性能问题

除了上面的工作以外还有个显而易见的问题:这种广告图片都是比较大的jpg图片(形状、色彩丰富),压缩的空间不大(jpg有损)。并且除了第一张,其他图片再3秒内是不需要显示的。所以决定分批下载,先下载第一张图,等第一张图下载完成之后再下载后续的图(这个时候这些图已经会排在下载队列的最后了)。

方案是扩展先前定义的initImages方法:

    function initImages(){
        var the = this;
        this.marquee.empty();//保持卫生
        this.appendImage(0, function(){
            for(var i=1; i<the.data.length; i++){
                the.appendImage(i);
            }
        });
    }

    function appendImage(index, callback){
        //检查参数,准备DOM对象... 
        img.load(callback);
        img.attr('src', data[0]);
        //插入DOM...
    }

菊花问题

图片延迟加载和以及本身就是靠js加载的第一张图片,必然会有概率发生图片还未加载完就要被用户观看的问题。所以必然要有野菊花。

解决方案更简单了,直接css加到了root元素的背景上,图片载入后自然盖住他,完美无缝,切换每张图没载入都可以显示到菊花。

js方面修改appendImage方法,防止未加载的图片被用户看到(那个飘渺的白框)。

    function appendImage(index, callback){
        //...
        img.hide();
        img.load(function(){
            $(this).show();
            callback();
        });
        img.attr('src', data[0]);
        //...
    }

其他问题

  1. 调整角标的显示逻辑,一次全部渲染,避免“跳”或乱序
  2. 调整轮播开始的逻辑,第一张图片加载完成后开始,保证广告的显示时间基本符合预期。
  3. 由于js放在页面底部,其实5张图片一起加载的性能差不多,兼容将第一张图片直接放在html中的情况。
@zhanyuzhang

This comment has been minimized.

Show comment
Hide comment
@zhanyuzhang

zhanyuzhang commented Jul 19, 2018

7777

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment