SlideView 图片滑动(扩展/收缩)展示效果

滑动展示效果主要用在图片或信息的滑动展示,也可以设置一下做成简单的口风琴(Accordion)效果。
这个其实就是以前写的图片滑动展示效果的改进版,那是我第一篇比较受关注的文章,是时候整理一下了。
有如下特色:
1,有四种方向模式选择;
2,结合tween算法实现多种滑动效果;
3,能自动根据滑动元素计算展示尺寸;
4,也可自定义展示或收缩尺寸;
5,可扩展自动切换功能;
6,可扩展滑动提示功能。
兼容: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

模式: 左边右边 默认索引: 无01234 尺寸: 按元素尺寸展示占一半展示200px收缩占十分一收缩80px
关闭: 自动不自动 速度: 默认快速慢速 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函数是这样的:

ExpandedBlockStart.gif 代码
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展示函数:

ExpandedBlockStart.gif 代码
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"定义一个能根据滑动元素获取提示元素的函数:

ExpandedBlockStart.gif 代码
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来筛选元素,注意可能包含多个样式,不能直接等于。

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

ExpandedBlockStart.gif 代码
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"中设置提示移动目标值:

ExpandedBlockStart.gif 代码
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//关闭时目标坐标


程序源码   

ExpandedBlockStart.gif 代码
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  =  { // 默认值
        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  =   0 this ._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  );
  }
};

 

自动展示扩展 

ExpandedBlockStart.gif 代码
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 );
    }
})();


提示信息扩展
 

ExpandedBlockStart.gif 代码
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 );
    }
})();

 

 完整实例下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值