zoukankan      html  css  js  c++  java
  • 《JavaScript 实战》:实现图片幻滑动展示效果

      滑动展示效果主要用在图片或信息的滑动展示,也可以设置一下做成简单的口风琴(Accordion)效果。这个其实就是以前写的图片滑动展示效果的改进版,那是我第一篇比较受关注的文章,是时候整理一下了。


    有如下特色:

    • 有四种方向模式选择;
    • 结合tween算法实现多种滑动效果;
    • 能自动根据滑动元素计算展示尺寸;
    • 也可自定义展示或收缩尺寸;
    • 可扩展自动切换功能;
    • 可扩展滑动提示功能。

    兼容:ie6/7/8, firefox 3.6.8, opera 10.51, safari 4.0.5, chrome 5.0


    效果预览

    • 0 0
    • 1 1
    • 2 2
    • 3 3
    • 4 4


    模式:

    默认索引:

    尺寸:


    关闭:

    速度:

    tween:


     



    图片滑动展示效果:



    仿口风琴(Accordion)效果:

    图片放大效果
    这个效果也叫放大镜效果,最早好像在ppg出现的,之后就有了很多仿制品出来了。好处是能在原图附近对图片进行局部放大查看,而且可以通过鼠标控制查看的部位。 查看全文
    Lazyload 延迟加载效果
    Lazyload是通过延迟加载来实现按需加载,达到节省资源,加快浏览速度的目的。网上也有不少类似的效果。 查看全文
    图片上传预览效果
    图片上传预览是一种在图片上传之前对图片进行本地预览的技术。使用户选择图片后能立即查看图片,而不需上传服务器,提高用户体验。 查看全文
    Tween算法及缓动效果
    Flash做动画时会用到Tween类,利用它可以做很多动画效果,例如缓动、弹簧等等。我这里要教大家的是怎么利用flash的Tween类的算法,来做js的Tween算法。 查看全文
    Table行定位效果
    近来有客户要求用table显示一大串数据,由于滚动后就看不到表头,很不方便,所以想到这个效果。 查看全文


    程序说明

    【基本原理】

    通过设置滑动元素的位置坐标(left/right/top/bottom),实现鼠标进入的目标元素滑动展示,其他元素滑动收缩的效果。
    难点是如何控制多个滑动元素同时进行不同的滑动,这里关键就在于把整体滑动分解成各个滑动元素进行各自的滑动。
    方法是给各个滑动元素设置目标值,然后各自向自己的目标值滑动,当全部都到达目标值就完成了。


    【容器设置】

    在_initContainer方法中进行容器设置,由于后面滑动参数的计算要用到容器,所以要先设置容器。
    先设置容器样式,要实现滑动需要设置容器相对或绝对定位,并且设置overflow为"hidden"来固定容器大小,而滑动元素也要设置绝对定位。

    鼠标移出容器时会触发_LEAVE移出函数:

    $$E.addEvent( container, "mouseleave"this._LEAVE );

    其中_LEAVE函数是这样的:

    代码
    var CLOSE = $$F.bind( this.close, this );
    this._LEAVE = $$F.bind( function(){
        clearTimeout(
    this._timerDelay);
        $$CE.fireEvent( 
    this"leave" );
        
    if ( this.autoClose ) { this._timerDelay = setTimeout( CLOSE, this.delay ); }
    }, 
    this );

    当autoClose属性为true时才会延时触发close方法。


    【滑动对象】

    程序初始化时会根据滑动元素创建滑动对象集合。
    先获取滑动元素:

    var nodes = opt.nodes ? $$A.map( opt.nodes, function(n) { return n; } )
        : $$A.filter( container.childNodes, function(n) { 
    return n.nodeType == 1; });

    如果没有自定义nodes滑动元素,就从容器获取childNodes作为滑动元素。
    还要用nodeType筛选一下,因为ie外的浏览器都会把空格作为childNodes的一部分。

    接着用获取的滑动元素生成程序需要的_nodes滑动对象集合:

    this._nodes = $$A.map( nodes, function(node){ return { "node": node }; });

    滑动对象用"node"属性记录滑动元素。

    然后在_initNodes方法中初始化滑动对象。
    每个滑动对象都有3个用来计算滑动目标值的属性:defaultTarget默认目标值,max展示尺寸,min收缩尺寸。
    如果有自定义max尺寸或min尺寸,会根据自定义的尺寸来计算。
    程序会优先按max来计算:

    max = Math.max( max <= 1 ? max * clientSize : Math.min( max, clientSize ), defaultSize );
    min 
    = ( clientSize - max ) / maxIndex;

    其中clientSize是容器的可见区域尺寸,defaultSize是平均分配尺寸。
    如果max是小数或1就按百分比计算,再把尺寸限制在defaultSize到clientSize的范围内。
    再计算减去max后其他收缩元素的平均尺寸,就可以得到min了。

    如果没有自定义max再按自定义min来计算:

    min = Math.min( min < 1 ? min * clientSize : min, defaultSize );
    max 
    = clientSize - maxIndex * min;

    同样,如果min是小数就按百分比计算,再做范围限制,然后计算得出max。

    最后得到自定义尺寸计算函数:

    getMax = function(){ return max; };
    getMin 
    = function(){ return min; };


    如果没有自定义max或min,就根据元素尺寸来计算:

    getMax = function(o){ return Math.max( Math.min( o.node[ offset ], clientSize ), defaultSize ); };
    getMin 
    = function(o){ return ( clientSize - o.max ) / maxIndex; };

    把元素尺寸作为展示尺寸来计算,同样要做范围限制,然后计算收缩尺寸。

    得到尺寸计算函数后,再用_each方法历遍并设置滑动对象:

    o.current = o.defaultTarget = getDefaultTarget(i);
    o.max 
    = getMax(o); o.min = getMin(o);

    其中current是当前坐标值,在移动计算时作为开始值的。
    而defaultTarget是默认目标值,即默认状态时移动的目标值,根据defaultSize和索引得到。

    还要设置当鼠标进入滑动元素时触发show展示函数:

    代码
    var node = o.node, SHOW = $$F.bind( this.show, this, i );
    o.SHOW 
    = $$F.bind( function(){
        clearTimeout(
    this._timerDelay);
        
    this._timerDelay = setTimeout( SHOW, this.delay );
        $$CE.fireEvent( 
    this"enter", i );
    }, 
    this );
    $$E.addEvent( node, 
    "mouseenter", o.SHOW );

    要在滑动元素的"mouseenter"事件中触发,并传递当前滑动对象的索引,再加上延时设置就可以了。


    【滑动展示】

    当鼠标进入其中一个滑动元素,就会触发show方法开始展示。

    首先执行_setMove方法设置滑动参数,并以索引作为参数。
    在_setMove里面主要是设置计算移动值时需要的目标值、开始值和变化值。
    先修正索引,错误的索引值会设置为0:

    this._index = index = index < 0 || index > maxIndex ? 0 : index | 0;


    再根据索引获取要展示的滑动对象,通过展示对象的min和max得到getTarget目标值函数:

    var nodeShow = nodes[ index ], min = nodeShow.min, max = nodeShow.max;
    getTarget 
    = function(o, i){ return i <= index ? min * i : min * ( i - 1 ) + max; };

    如果滑动对象就是展示对象或者在展示对象前面,目标值就是min * i,因为第i+1个滑动对象的目标值就是i个min的大小。
    否则,目标值就是min * ( i - 1 ) + max,其实就是把展示对象的位置换成max。

    然后设置每个滑动对象的参数属性:

    this._each( function(o, i){
        o.target 
    = getTarget(o, i);
        o.begin 
    = o.current;
        o.change 
    = o.target - o.begin;
    });

    其中target记录目标值,begin通过current得到开始值,目标值和开始值的差就是change改变值。

    设置完成后,就执行_easeMove方法开始滑移,在里面重置_time属性为0,再就执行_move程序就正式开始移动了。
    首先判断_time是否到达duration持续时间,没有到达的话,就继续移动。
    程序设置了一个_tweenMove移动函数,用来设置缓动:

    this._setPos( function(o) {
        
    return this.tween( this._time, o.begin, o.change, this.duration );
    });

    利用tween算法,结合当前时间,开始值,改变值和持续时间,就能得到当前要移动的坐标值。
    ps:关于tween缓动可以参考tween算法及缓动效果

    当_time到达duration说明滑动已经完成,再执行一次_targetMove目标值移动函数:

    this._setPos( function(o) { return o.target; } );

    直接移动到目标值,可以防止可能出现的计算误差导致移位不准确。


    【关闭和重置】

    close方法可以关闭展示,即滑动到默认状态,默认在移出容器时就会执行。
    默认状态是指全部滑动元素位于defaultTarget默认目标值的状态。
    先用_setMove设置移动参数,当_setMove没有索引参数时,就会设置目标值为默认目标值:

    getTarget = function(o){ return o.defaultTarget; }

    完成参数设置后,再执行_easeMove进行滑动,跟滑动展示类似。

    reset方法可以重置展示,重置的意思是不进行滑动而直接移动到目标值。
    如果没有索引参数,就会直接执行_defaultMove默认值移动函数:

    this._setPos( function(o) { return o.defaultTarget; } );

    直接把滑动元素移动到默认状态。
    如果有索引参数,就先用_setMove根据索引设置目标值,再执行_targetMove直接移动到目标值。
    程序初始化后会执行一次reset,并且以自定义defaultIndex作为参数。
    利用defaultIndex可以一开始就展示对应索引的滑动对象。


    【方向模式】

    程序可以自定义mode方向模式,有四种方向模式:bottom、top、right、left(默认)。
    其中right和left是在水平方向滑动,而bottom和top是在垂直方向滑动。
    而right和left的区别是定点方向不同,left以左边为定点在右边滑动,right就相反。
    具体参考实例就应该明白了,bottom和top的区别也类似。

    程序是通过对不同的方向就修改对应方向的坐标样式来实现的。
    例如left模式就用"left"样式来做移动效果,top模式就用"top"样式。
    初始化程序中设置的_pos属性就是用来记录当前模式要使用的坐标样式的:

    this._pos = /^(bottom|top|right|left)$/.test( opt.mode.toLowerCase() ) ? RegExp.$1 : "left";

    然后在_setPos方法中使用_pos指定的坐标样式来设置坐标值:

    var pos = this._pos;
    this._each( function(o, i) {
        o.node.style[ pos ] 
    = (o.current = Math.round(method.call( this, o ))) + "px";
    });

    而_horizontal属性就记录了是否水平方向滑动,即是否right或left。
    在计算尺寸时,通过它来指定使用用水平还是垂直方向的尺寸。

    还有一个_reverse属性,判断是否bottom或right模式。
    这个属性是为了解决一个问题,例如right模式要实现类似下面的效果:

    2
    1
    0


    有两种方法,可以调整元素插入顺序:

    <div class="container">
        
    <div style="right:0;">2</div>
        <div style="right:100px;">1</div>
        <div style="right:200px;">0</div>
    </div>

    但这样需要修改dom结构,或者通过zIndex设置堆叠顺序:

    <div class="container">
        
    <div style="right:200px;z-index:3;">0</div>
        <div style="right:100px;z-index:2;">1</div>
        <div style="right:0;z-index:1;">2</div>
    </div>

    显然设置zIndex的方法比较好,程序也用了这个方法。
    程序就是用_reverse属性来判断是否需要做这些修正。

    首先在_initContainer中,根据_reverse重新设置zIndex:

    var zIndex = 100, gradient = this._reverse ? -1 : 1;
    this._each( function(o){
        
    var style = o.node.style;
        style.position 
    = "absolute"; style.zIndex = zIndex += gradient;
    });


    在_initNodes中,获取默认目标值时也要判断:

    getDefaultTarget = this._reverse
        
    ? function(i){ return defaultSize * ( maxIndex - i ); }
        : function(i){ 
    return defaultSize * i; },

    当_reverse为true时,由于定点位置是在索引的反方向,设置元素时也应该倒过来设的,所以要用maxIndex减一下。

    在_setMove中,根据索引设置滑动目标值时,也要判断:

    if ( this._reverse ) {
        var 
    get = getTarget;
        index 
    = maxIndex - index;
        getTarget 
    = function(o, i){ return get( o, maxIndex - i ); }
    }

    不但滑动对象集合的索引要修正,展示对象的索引也要修正。


    【自动展示扩展】

    这次扩展用的是组合模式,原理参考的ImageZoom扩展篇的扩展模式部分
    不同的是加了一个属性扩展,用来添加扩展方法:

    $$.extend( this, prototype );

    注意不能添加到SlideView.prototype,这样会影响到SlideView的结构。

    “自动展示”要实现的是滑动对象自动轮流展示,并且取消默认状态而实行强制展示,可以用在图片的轮换展示。
    只要在SlideView后面加入自动展示扩展程序,并且auto参数设为true就会启用。
    原理也很简单,就是每次滑动/移动完成后,用定时器执行下一次滑动就行了。

    首先在"init"初始化程序中,增加一个_NEXT程序,用来展示下一个滑动对象:

    this._NEXT = $$F.bind( function(){ this.show( this._index + 1 ); }, this );

    其实就是把当前索引_index加1之后作为show的参数执行。
    再增加一个_autoNext方法:

    if ( !this._autoPause ) {
        clearTimeout(
    this._autoTimer);
        
    this._autoTimer = setTimeout( this._NEXT, this.autoDelay );
    }

    作用是延时执行_NEXT程序,并且有一个_autoPause属性用来锁定执行。

    然后设置几个需要执行的地方。
    首先在"finish"完成滑动事件中,执行_autoNext方法,这样就实现了基本的自动展示了。
    在鼠标进入滑动元素后,应该停止自动切换,所以在"enter"进入滑动元素事件中,会清除定时器并把_autoPause设为true来锁定。
    对应地在"leave"鼠标离开容器事件中,要把_autoPause设回false解除锁定,再执行_autoNext方法重新启动自动程序。
    并且在"leave"中设置autoClose为false,防止自动恢复默认状态。

    最后还要重写reset:

    reset.call( this, index == undefined ? this._index : index );
    this._autoNext();

    重写后的reset会强制设置索引来展示,并执行_autoNext进行下一次滑动。


    【提示信息扩展】

    “提示信息”效果是指每个滑动对象对应有一个提示信息(内容)的层(元素)。
    这个提示信息会在滑动对象展示时展示,收缩和关闭时关闭。
    只要加入提示信息扩展程序,并且tip参数设为true就会启用。

    提示扩展支持四种位置提示:bottom、top、right、left。
    在"init"中,根据自定义tipMode获取_tipPos坐标样式:

    this._tipPos = /^(bottom|top|right|left)$/.test( this.options.tipPos.toLowerCase() ) ? RegExp.$1 : "bottom";


    接着在"initNodes"定义一个能根据滑动元素获取提示元素的函数:

    代码
    var opt = this.options, tipTag = opt.tipTag, tipClass = opt.tipClass,
        re 
    = tipClass && new RegExp("(^|\s)" + tipClass + "(\s|$)"),
        getTipNode 
    =  function(node){
            var nodes 
    = node.getElementsByTagName( tipTag );
            
    if ( tipClass ) {
                nodes 
    = $$A.filter( nodes, function(n){ return re.test(n.className); } );
            }
            
    return nodes[0];
        };

    如果自定义了tipTag,就会根据标签来获取元素,否则就按默认值"*"获取全部元素。
    如果自定义了tipClass,就会再根据className来筛选元素,注意可能包含多个样式,不能直接等于。

    得到函数后,再创建提示对象:

    代码
    this._each( function(o) {
        var node 
    = o.node, tipNode = getTipNode(node);
        node.style.overflow 
    = "hidden";
        tipNode.style.position 
    = "absolute"; tipNode.style.left = 0;
        
        o.tip 
    = {
            
    "node": tipNode,
            
    "show": tipShow != undefined ? tipShow : 0,
            
    "close": tipClose != undefined ? tipClose : -tipNode[offset]
        };
    });

    先获取提示元素,并设置相关样式,再给滑动对象添加一个tip属性,保存对应的提示对象。
    其中"node"属性保存提示元素,"show"是展示时的坐标值,"close"是关闭时的坐标值。
    如果没有自定义tipShow,默认展示时坐标值是0,即提示元素刚好贴在滑动元素边上的位置;
    如果没有自定义tipClose,默认关闭时坐标是提示元素的尺寸,即提示元素刚好隐藏在滑动元素外面的位置。

    在"setMove"中设置提示移动目标值:

    代码
    var maxIndex = this._nodes.length - 1;
    this._each( function(o, i) {
        var tip 
    = o.tip;
        
    if ( this._reverse ) { i = maxIndex -i; }
        tip.target 
    = index == undefined || index != i ? tip.close : tip.show;
        tip.begin 
    = tip.current; tip.change = tip.target - tip.begin;
    });

    这个比滑动对象的设置简单得多,当设置了index参数,并且index等于该滑动对象的索引时才需要展示,其他情况都是隐藏。
    要注意,跟滑动对象一样,在_reverse为true的时候需要修正索引。
    在"tweenMove"、"targetMove"、"defaultMove"也要设置对应的移动函数。

    为了方便样式设置,扩展了一个_setTipPos方法:

    var pos = this._tipPos;
    this._each( function(o, i) {
        var tip 
    = o.tip;
        tip.node.style[ pos ] 
    = (tip.current = method.call( this, tip )) + "px";
    });

    根据_tipPos坐标样式来设置坐标值。


    使用技巧

    【展示尺寸】

    要自定义展示尺寸可以通过max和min来设置,可以按像素或百分比来计算。
    如果不设置的话,就会按照元素本身的尺寸来展示。
    所以滑动元素展示的尺寸并不需要一致的,程序可以自动计算。

    【Accordion效果】

    Accordion是可折叠的面板控件,效果类似手风琴,SlideView通过设置也能做到类似的效果。
    首先把autoClose设为false取消自动关闭,再设置defaultIndex,使SlideView处于展开状态不会关闭。
    一般Accordion都有一个固定尺寸的标题,这个可以用min来设置。
    这样就实现了简单的Accordion效果,具体参考第三个实例。


    使用说明

    实例化时,必须有容器对象或id作为参数:

    new SlideView( "idSlideView" );


    可选参数用来设置系统的默认属性,包括:
    属性:    默认值//说明
    nodes:   null,//自定义展示元素集合
    mode:   "left",//方向
    max:   0,//展示尺寸(像素或百分比)
    min:   0,//收缩尺寸(像素或百分比)
    delay:   100,//触发延时
    interval:  20,//滑动间隔
    duration:  20,//滑动持续时间
    defaultIndex: null,//默认展示索引
    autoClose:  true,//是否自动恢复
    tween:   function(t,b,c,d){ return -c * ((t=t/d-1)*t*t*t - 1) + b; },//tween算子
    onShow:   function(index){},//滑动展示时执行
    onClose:  function(){}//滑动关闭执行
    其中interval、delay、duration、tween、autoClose、onShow、onClose属性可以在程序初始化后动态设置。

    还提供了以下方法:
    show:根据索引滑动展示;
    close:滑动到默认状态;
    reset:重置为默认状态或展开索引对应滑动对象;
    dispose:销毁程序。

    要使用自动展示,只要在SlideView后面加入自动展示扩展程序,并且auto参数设为true即可。
    新增如下可选参数:
    autoDelay: 2000//展示时间

    要使用提示信息,只要加入提示信息扩展程序,并且tip参数设为true即可。
    新增如下可选参数:
    属性:    默认值//说明
    tipPos:  "bottom",//提示位置
    tipTag:  "*",//提示元素标签
    tipClass: "",//提示元素样式
    tipShow: null,//展示时目标坐标
    tipClose: null//关闭时目标坐标


    程序源码   

    代码
    var SlideView = function(container, options){
        
    this._initialize( container, options );
        
    this._initContainer();
        
    this._initNodes();
        
    this.reset( this.options.defaultIndex );
    };
    SlideView.prototype 
    = {
      
    //初始化程序
      _initialize: function(container, options) {
        
        
    var container = this._container = $$(container);//容器对象
        this._timerDelay = null;//延迟计时器
        this._timerMove = null;//移动计时器
        this._time = 0;//时间
        this._index = 0;//索引
        
        
    var opt = this._setOptions(options);
        
        
    this.interval = opt.interval | 0;
        
    this.delay = opt.delay | 0;
        
    this.duration = opt.duration | 0;
        
    this.tween = opt.tween;
        
    this.autoClose = !!opt.autoClose;
        
    this.onShow = opt.onShow;
        
    this.onClose = opt.onClose;
        
        
    //设置参数
        var pos =this._pos = /^(bottom|top|right|left)$/.test( opt.mode.toLowerCase() ) ? RegExp.$1 : "left";
        
    this._horizontal = /right|left/.test( this._pos );
        
    this._reverse = /bottom|right/.test( this._pos );
        
        
    //获取滑动元素
        var nodes = opt.nodes ? $$A.map( opt.nodes, function(n) { return n; } )
            : $$A.filter( container.childNodes, 
    function(n) { return n.nodeType == 1; });
        
    //创建滑动对象集合
        this._nodes = $$A.map( nodes, function(node){
            
    var style = node.style;
            
    return { "node": node, "style": style[pos], "position": style.position, "zIndex": style.zIndex };
        });
        
        
    //设置程序
        this._MOVE = $$F.bind( this._move, this );
        
        
    var CLOSE = $$F.bind( this.close, this );
        
    this._LEAVE = $$F.bind( function(){
            clearTimeout(
    this._timerDelay);
            $$CE.fireEvent( 
    this"leave" );
            
    if ( this.autoClose ) { this._timerDelay = setTimeout( CLOSE, this.delay ); }
        }, 
    this );
        
        $$CE.fireEvent( 
    this"init" );
      },
      
    //设置默认属性
      _setOptions: function(options) {
        
    this.options =nbsp;{//默认值
            nodes:            null,//自定义展示元素集合
            mode:            "left",//方向
            max:            0,//展示尺寸(像素或百分比)
            min:            0,//收缩尺寸(像素或百分比)
            delay:            100,//触发延时
            interval:        20,//滑动间隔
            duration:        20,//滑动持续时间
            defaultIndex:    null,//默认展示索引
            autoClose:        true,//是否自动恢复
            tween:            function(t,b,c,d){ return -* ((t=t/d-1)*t*t*t - 1) + b; },//tween算子
            onShow:            function(index){},//滑动展示时执行
            onClose:        function(){}//滑动关闭执行
        };
        
    return $$.extend(this.options, options || {});
      },
      
    //设置容器
      _initContainer: function() {
        
    //容器样式设置
        var container = this._container, style = container.style, position = $$D.getStyle( container, "position" );
        
    this._style = { "position": style.position, "overflow": style.overflow };//备份样式
        if ( position != "relative" && position != "absolute" ) { style.position = "relative"; }
        style.overflow 
    = "hidden";
        
    //移出容器时
        $$E.addEvent( container, "mouseleave"this._LEAVE );
        
    //设置滑动元素
        var zIndex = 100, gradient = this._reverse ? -1 : 1;
        
    this._each( function(o){
            
    var style = o.node.style;
            style.position 
    = "absolute"; style.zIndex = zIndex += gradient;
        });
        
        $$CE.fireEvent( 
    this"initContainer" );
      },
      
    //设置滑动对象
      _initNodes: function() {
        
    var len = this._nodes.length, maxIndex = len - 1,
            type 
    = this._horizontal ? "Width" : "Height", offset = "offset" + type,
            clientSize 
    = this._container[ "client" + type ],
            defaultSize 
    = Math.round( clientSize / len ),
            
    //计算默认目标值的函数
            getDefaultTarget = this._reverse
                
    ? function(i){ return defaultSize * ( maxIndex - i ); }
                : 
    function(i){ return defaultSize * i; },
            max 
    = this.options.max, min = this.options.min, getMax, getMin;
        
    //设置参数函数
        if ( max > 0 || min > 0 ) {//自定义参数值
            //小数按百分比设置
            if ( max > 0  ) {
                max 
    = Math.max( max <= 1 ? max * clientSize : Math.min( max, clientSize ), defaultSize );
                min 
    = ( clientSize - max ) / maxIndex;
            } 
    else {
                min 
    = Math.min( min < 1 ? min * clientSize : min, defaultSize );
                max 
    = clientSize - maxIndex * min;
            }
            getMax 
    = function(){ return max; };
            getMin 
    = function(){ return min; };
        } 
    else {//根据元素尺寸设置参数值
            getMax = function(o){ return Math.max( Math.min( o.node[ offset ], clientSize ), defaultSize ); };
            getMin 
    = function(o){ return ( clientSize - o.max ) / maxIndex; };
        }
        
        
    //设置滑动对象
        this._each( function(o, i){
            
    //移入滑动元素时执行程序
            var node = o.node, SHOW = $$F.bind( this.show, this, i );
            o.SHOW 
    = $$F.bind( function(){
                clearTimeout(
    this._timerDelay);
                
    this._timerDelay = setTimeout( SHOW, this.delay );
                $$CE.fireEvent( 
    this"enter", i );
            }, 
    this );
            $$E.addEvent( node, 
    "mouseenter", o.SHOW );
            
    //计算尺寸
            o.current = o.defaultTarget = getDefaultTarget(i);//默认目标值
            o.max = getMax(o); o.min = getMin(o);
        });
        
        $$CE.fireEvent( 
    this"initNodes" );
      },
      
      
    //根据索引滑动展示
      show: function(index) {
        
    this._setMove( index | 0 );
        
    this.onShow( this._index );
        
    this._easeMove();
      },
      
    //滑动到默认状态
      close: function() {
        
    this._setMove();
        
    this.onClose();
        
    this._easeMove();
      },
      
    //重置为默认状态或展开索引对应滑动对象
      reset: function(index) {
        clearTimeout(
    this._timerDelay);
        
    if ( index == undefined ) {
            
    this._defaultMove();
        } 
    else {
            
    this._setMove(index);
            
    this.onShow( this._index );
            
    this._targetMove();
        }
      },
      
      
    //设置滑动参数
      _setMove: function(index) {
        
    var setTarget;//设置目标值函数
        if ( index == undefined ) {//设置默认状态目标值
            getTarget = function(o){ return o.defaultTarget; }
        } 
    else {//根据索引设置滑动目标值
            var nodes = this._nodes, maxIndex = nodes.length - 1;
            
    //设置索引
            this._index = index = index < 0 || index > maxIndex ? 0 : index | 0;
            
    //设置展示参数
            var nodeShow = nodes[ index ], min = nodeShow.min, max = nodeShow.max;
            getTarget 
    = function(o, i){ return i <= index ? min * i : min * ( i - 1 ) + max; };
            
    if ( this._reverse ) {
                
    var get = getTarget;
                index 
    = maxIndex - index;
                getTarget 
    = function(o, i){ return get( o, maxIndex - i ); }
            }
        }
        
    this._each( function(o, i){
            o.target 
    = getTarget(o, i);//设置目标值
            o.begin = o.current;//设置开始值
            o.change = o.target - o.begin;//设置变化值
        });
        $$CE.fireEvent( 
    this"setMove", index );
      },
      
      
    //滑移程序
      _easeMove: function() {
        
    this._time = 0this._move();
      },
      
    //移动程序
      _move: function() {
        
    if ( this._time < this.duration ){//未到达
            this._tweenMove();
            
    this._time++;
            
    this._timerMove = setTimeout( this._MOVE, this.interval );
        } 
    else {//完成
            this._targetMove();//防止计算误差
            $$CE.fireEvent( this"finish" );
        }
      },
      
      
    //tween移动函数
      _tweenMove: function() {
        
    this._setPos( function(o) {
            
    return this.tween( this._time, o.begin, o.change, this.duration );
        });
        $$CE.fireEvent( 
    this"tweenMove" );
      },
      
    //目标值移动函数
      _targetMove: function() {
        
    this._setPos( function(o) { return o.target; } );
        $$CE.fireEvent( 
    this"targetMove" );
      },
      
    //默认值移动函数
      _defaultMove: function() {
        
    this._setPos( function(o) { return o.defaultTarget; } );
        $$CE.fireEvent( 
    this"defaultMove" );
      },
      
    //设置坐标值
      _setPos: function(method) {
        clearTimeout(
    this._timerMove);
        
    var pos = this._pos;
        
    this._each( function(o, i) {
            o.node.style[ pos ] 
    = (o.current = Math.round(method.call( this, o ))) + "px";
        });
      },
      
      
    //历遍滑动对象集合
      _each: function(callback) {
        $$A.forEach( 
    this._nodes, callback, this );
      },
      
      
    //销毁程序
      dispose: function() {
        clearTimeout(
    this._timerDelay);
        clearTimeout(
    this._timerMove);
        
        $$CE.fireEvent( 
    this"dispose" );
        
        
    var pos = this._pos;
        
    this._each( function(o) {
            
    var style = o.node.style;
            style[pos] 
    = o.style; style.zIndex = o.zIndex; style.position = o.position;//恢复样式
            $$E.removeEvent( o.node, "mouseenter", o.SHOW ); o.SHOW = o.node = null;
        });
        $$E.removeEvent( 
    this._container, "mouseleave"this._LEAVE );
        
        $$D.setStyle( 
    this._container, this._style );
        
        
    this._container = this._nodes = this._MOVE = this._LEAVE = null;
        $$CE.clearEvent( 
    this );
      }
    };

    自动展示扩展 

    代码
    SlideView.prototype._initialize = (function(){
        
    var init = SlideView.prototype._initialize,
            reset 
    = SlideView.prototype.reset,
            methods 
    = {
                
    "init"function(){
                    
    this.autoDelay = this.options.autoDelay | 0;
                    
                    
    this._autoTimer = null;//定时器
                    this._autoPause = false;//暂停自动展示
                    //展示下一个滑动对象
                    this._NEXT = $$F.bind( function(){ this.show( this._index + 1 ); }, this );
                },
                
    "leave"function(){
                    
    this.autoClose = this._autoPause = false;
                    
    this._autoNext();
                },
                
    "enter"function(){
                    clearTimeout(
    this._autoTimer);
                    
    this._autoPause = true;
                },
                
    "finish"function(){
                    
    this._autoNext();
                },
                
    "dispose"function(){
                    clearTimeout(
    this._autoTimer);
                }
            },
            prototype 
    = {
                _autoNext: 
    function(){
                    
    if ( !this._autoPause ) {
                        clearTimeout(
    this._autoTimer);
                        
    this._autoTimer = setTimeout( this._NEXT, this.autoDelay );
                    }
                },
                reset: 
    function(index) {
                    reset.call( 
    this, index == undefined ? this._index : index );
                    
    this._autoNext();
                }
            };
        
    return function(){
            
    var options = arguments[1];
            
    if ( options && options.auto ) {
                
    //扩展options
                $$.extend( options, {
                    autoDelay:    
    2000//展示时间
                }, false );
                
    //扩展属性
                $$.extend( this, prototype );
                
    //扩展钩子
                $$A.forEach( methods, function( method, name ){
                    $$CE.addEvent( 
    this, name, method );
                }, 
    this );
            }
            init.apply( 
    this, arguments );
        }
    })();


    提示信息扩展
     

    代码
    SlideView.prototype._initialize = (function(){
        
    var init = SlideView.prototype._initialize,
            methods 
    = {
                
    "init"function(){
                    
    //坐标样式
                    this._tipPos = /^(bottom|top|right|left)$/.test( this.options.tipPos.toLowerCase() ) ? RegExp.$1 : "bottom";
                },
                
    "initNodes"function(){
                    
    var opt = this.options, tipTag = opt.tipTag, tipClass = opt.tipClass,
                        re 
    = tipClass && new RegExp("(^|\s)" + tipClass + "(\s|$)"),
                        getTipNode 
    =  function(node){
                            
    var nodes = node.getElementsByTagName( tipTag );
                            
    if ( tipClass ) {
                                nodes 
    = $$A.filter( nodes, function(n){ return re.test(n.className); } );
                            }
                            
    return nodes[0];
                        };
                    
    //设置提示对象
                    var tipShow = opt.tipShow, tipClose = opt.tipClose,
                        offset 
    = /right|left/.test( this._tipPos ) ? "offsetWidth" : "offsetHeight";
                    
    this._each( function(o) {
                        
    var node = o.node, tipNode = getTipNode(node);
                        node.style.overflow 
    = "hidden";
                        tipNode.style.position 
    = "absolute"; tipNode.style.left = 0;
                        
    //创建提示对象
                        o.tip = {
                            
    "node": tipNode,
                            
    "show": tipShow != undefined ? tipShow : 0,
                            
    "close": tipClose != undefined ? tipClose : -tipNode[offset]
                        };
                    });
                },
                
    "setMove"function(index){
                    
    var maxIndex = this._nodes.length - 1;
                    
    this._each( function(o, i) {
                        
    var tip = o.tip;
                        
    if ( this._reverse ) { i = maxIndex -i; }
                        tip.target 
    = index == undefined || index != i ? tip.close : tip.show;
                        tip.begin 
    = tip.current; tip.change = tip.target - tip.begin;
                    });
                },
                
    "tweenMove"function(){
                    
    this._setTipPos( function(tip) {
                        
    return Math.round( this.tween( this._time, tip.begin, tip.change, this.duration ) );
                    });
                },
                
    "targetMove"function(){
                    
    this._setTipPos( function(tip){ return tip.target; });
                },
                
    "defaultMove"function(){
                    
    this._setTipPos( function(tip){ return tip.close; });
                },
                
    "dispose"function(){
                    
    this._each( function(o){ o.tip = null; });
                }
            },
            prototype 
    = {
                
    //设置坐标值函数
                _setTipPos: function(method) {
                    
    var pos = this._tipPos;
                    
    this._each( function(o, i) {
                        
    var tip = o.tip;
                        tip.node.style[ pos ] 
    = (tip.current = method.call( this, tip )) + "px";
                    });
                }
            };
        
    return function(){
            
    var options = arguments[1];
            
    if ( options && options.tip == true ) {
                
    //扩展options
                $$.extend( options, {
                    tipPos:        
    "bottom",//提示位置
                    tipTag:        "*",//提示元素标签
                    tipClass:    "",//提示元素样式
                    tipShow:    null,//展示时目标坐标
                    tipClose:    null//关闭时目标坐标
                }, false );
                
    //扩展属性
                $$.extend( this, prototype );
                
    //扩展钩子
                $$A.forEach( methods, function( method, name ){
                    $$CE.addEvent( 
    this, name, method );
                }, 
    this );
            }
            init.apply( 
    this, arguments );
        }
    })();

     完整实例下载

    本文链接:http://www.cnblogs.com/oooweb/p/javascript-slider-view.html

    原文出处:coudgamer

  • 相关阅读:
    SpringBoot+EasyCaptcha实现验证码功能
    Spring boot集成Swagger
    Swagger注释API :@ApiModel
    lombok的@Accessors注解3个属性说明
    lombok——@EqualsAndHashCode(callSuper = true)注解的使用
    Springboot集成分页插件PageHelper
    SprinBoot application.properties配置详情之DataSource
    SpringBoot系列之banner.txt (转)
    C语言基础知识汇总
    Byte、KB、MB、GB、TB、PB、EB是啥以及它们之间的进率
  • 原文地址:https://www.cnblogs.com/oooweb/p/javascript-slider-view.html
Copyright © 2011-2022 走看看