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


Posted in Javascript onAugust 01, 2010

这个其实就是以前写的图片滑动展示效果的改进版,那是我第一篇比较受关注的文章,是时候整理一下了。
有如下特色:
1,有四种方向模式选择;
2,结合tween算法实现多种滑动效果;
3,能自动根据滑动元素计算展示尺寸;
4,也可自定义展示或收缩尺寸;
5,可扩展自动切换功能;
6,可扩展滑动提示功能。
兼容:ie6/7/8, firefox 3.6.8, opera 10.51, safari 4.0.5, chrome 5.0

程序说明

【基本原理】

通过设置滑动元素的位置坐标(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模式。

<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 = {//默认值 
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(){}//滑动关闭执行 
}; 
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 ); 
} 
};

自动展示扩展

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/cloudgamer/archive/2010/07/29/SlideView.html

Javascript 相关文章推荐
js字符编码函数区别分析
Jun 05 Javascript
js 小数取整的函数
May 10 Javascript
jQuery插件开发全解析
Oct 10 Javascript
JavaScript高级程序设计(第3版)学习笔记8 js函数(中)
Oct 11 Javascript
新增加的内容是如何将div的scrollbar自动移动最下面
Jan 02 Javascript
jquery可定制的在线UEditor编辑器
Nov 17 Javascript
基于javascript实现tab切换特效
Mar 29 Javascript
jQuery旋转插件jqueryrotate用法详解
Oct 13 Javascript
Angular中$broadcast和$emit的使用方法详解
May 22 Javascript
Angular动态绑定样式及改变UI框架样式的方法小结
Sep 03 Javascript
如何在项目中使用log4.js的方法步骤
Jul 16 Javascript
浅谈Vue2.4.0 $attrs与inheritAttrs的具体使用
Mar 08 Javascript
JavaScript和ActionScript的交互实现代码
Aug 01 #Javascript
JavaScript判断窗口是否最小化的代码(跨浏览器)
Aug 01 #Javascript
jquery下onpropertychange事件的绑定方法
Aug 01 #Javascript
关于this和self的使用说明
Aug 01 #Javascript
ajax 缓存 问题 requestheader
Aug 01 #Javascript
parseInt parseFloat js字符串转换数字
Aug 01 #Javascript
style、 currentStyle、 runtimeStyle区别分析
Aug 01 #Javascript
You might like
PHP MYSQL实现登陆和模糊查询两大功能
2016/02/05 PHP
Yii视图操作之自定义分页实现方法
2016/07/14 PHP
PHP基于DOMDocument解析和生成xml的方法分析
2017/07/17 PHP
PHP实现将几张照片拼接到一起的合成图片功能【便于整体打印输出】
2017/11/14 PHP
laravel-admin 实现给grid的列添加行数序号的方法
2019/10/08 PHP
PHP7 整型处理机制修改
2021/03/09 PHP
解决jquery .ajax 在IE下卡死问题的解决方法
2009/10/26 Javascript
jQuery的Ajax时无响应数据的解决方法
2010/05/25 Javascript
JavaScript高级程序设计 阅读笔记(十八) js跨平台的事件
2012/08/14 Javascript
js open() 与showModalDialog()方法使用介绍
2013/09/10 Javascript
JQUERY 设置SELECT选中项代码
2014/02/07 Javascript
从数据库读取数据后将其输出成html标签的三种方法
2014/10/13 Javascript
jQuery根据用户电脑是mac还是pc加载对应样式的方法
2015/06/26 Javascript
jquery选择器简述
2015/08/31 Javascript
简单实现IONIC购物车功能
2017/01/10 Javascript
原生js实现简单的Ripple按钮实例代码
2017/03/24 Javascript
微信小程序实现登录注册功能
2020/12/29 Javascript
微信小程序 接入腾讯地图的两种写法
2021/01/12 Javascript
js数组的基本使用总结
2021/01/18 Javascript
[47:36]Optic vs Newbee 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/18 DOTA
零基础写python爬虫之HTTP异常处理
2014/11/05 Python
django Admin文档生成器使用详解
2019/07/22 Python
python制作朋友圈九宫格图片
2019/11/03 Python
Python 词典(Dict) 加载与保存示例
2019/12/06 Python
selenium学习教程之定位以及切换frame(iframe)
2021/01/04 Python
详解python第三方库的安装、PyInstaller库、random库
2021/03/03 Python
Herschel Supply Co.美国:背包、手提袋及配件
2020/11/24 全球购物
机械系大学毕业生推荐信
2013/11/27 职场文书
小学生竞选班长演讲稿
2014/04/24 职场文书
促销活动总结范文
2014/04/30 职场文书
2014年小学教师工作自我评价
2014/09/22 职场文书
护理见习报告范文
2014/11/03 职场文书
行政处罚告知书
2015/07/01 职场文书
大学升旗仪式主持词
2015/07/04 职场文书
2016年“抗战胜利纪念日”71周年校园广播稿
2015/12/18 职场文书
用Python仅20行代码编写一个简单的端口扫描器
2022/04/08 Python