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 屏蔽键盘不可用与鼠标右键不可用的方法
Nov 18 Javascript
node.js中的fs.linkSync方法使用说明
Dec 15 Javascript
javascript手工制作悬浮菜单
Feb 12 Javascript
javascript获取元素离文档各边距离的方法
Feb 13 Javascript
详解JavaScript正则表达式中的global属性的使用
Jun 16 Javascript
基于JavaScript实现屏幕滚动效果
Jan 18 Javascript
jQuery实现鼠标悬停3d菜单展开动画效果
Jan 19 Javascript
解决BootStrap Fileinput手机图片上传显示旋转问题
Jun 01 Javascript
微信小程序使用progress组件实现显示进度功能【附源码下载】
Dec 12 Javascript
jquery实现企业定位式导航效果
Jan 01 jQuery
React+TypeScript+webpack4多入口配置详解
Aug 08 Javascript
vue.js+ElementUI实现进度条提示密码强度效果
Jan 18 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
2019年漫画销量排行榜:鬼灭登顶 海贼单卷制霸 尾田盛赞鬼灭
2020/03/08 日漫
用PHP调用Oracle存储过程
2006/10/09 PHP
ThinkPHP有变量的where条件分页实例
2014/11/03 PHP
简单的php+mysql聊天室实现方法(附源码)
2016/01/05 PHP
cnblogs csdn 代码运行框实现代码
2009/11/02 Javascript
jQuery 表单验证扩展(四)
2010/10/20 Javascript
网页源代码保护(禁止右键、复制、另存为、查看源文件)
2012/05/23 Javascript
jquery为页面增加快捷键示例
2014/01/31 Javascript
JavaScript日期时间与时间戳的转换函数分享
2015/01/31 Javascript
JQuery在循环中绑定事件的问题详解
2016/06/02 Javascript
ES6新特性之类(Class)和继承(Extends)相关概念与用法分析
2017/05/24 Javascript
让nodeJS支持ES6的词法----babel的安装和使用方法
2017/07/31 NodeJs
详解使用Typescript开发node.js项目(简单的环境配置)
2017/10/09 Javascript
vue实现底部菜单功能
2018/07/24 Javascript
cdn模式下vue的基本用法详解
2018/10/07 Javascript
vue router总结 $router和$route及router与 router与route区别
2019/07/05 Javascript
JS中的算法与数据结构之二叉查找树(Binary Sort Tree)实例详解
2019/08/16 Javascript
深入理解令牌认证机制(token)
2019/08/22 Javascript
vue中destroyed方法的使用说明
2020/07/21 Javascript
JavaScript 实现轮播图特效的示例
2020/11/05 Javascript
python实现telnet客户端的方法
2015/04/15 Python
Python基于有道实现英汉字典功能
2015/07/25 Python
详解从Django Rest Framework响应中删除空字段
2019/01/11 Python
你可能不知道的Python 技巧小结
2020/01/29 Python
Python多线程Threading、子线程与守护线程实例详解
2020/03/24 Python
使用pycharm和pylint检查python代码规范操作
2020/06/09 Python
python关于倒排列的知识点总结
2020/10/13 Python
浅谈基于Canvas的手绘风格图形库Rough.js
2018/03/19 HTML / CSS
《望洞庭》教学反思
2014/02/16 职场文书
财务部总监岗位职责
2014/03/12 职场文书
《登鹳雀楼》教学反思
2014/04/09 职场文书
幼儿园清明节活动总结
2014/07/04 职场文书
个人作风建设总结
2014/10/23 职场文书
高一军训感想
2015/08/07 职场文书
2016母亲节感恩话语
2015/12/09 职场文书
《西游记》读后感(3篇)
2019/09/20 职场文书