【CSON原创】 图片滑动展开效果发布

功能说明:

鼠标移动到不同图片上,该图片滑动展开,其它图片折叠。

支持IE 6 7 8 firefox chrome

效果预览:

 

r_cat1.jpg r_cat2.jpg r_cat3.jpg r_cat4.jpg r_cat5.jpg

实现原理:

当鼠标移动到某张图片,该图片以及该图片前的图片以相同速度向左运动,该图片之后的图片也以相同速度向右运动,形成展开选中图片的效果。

代码分析:

 
  
var flow_slide_imgs = function (options) {
this ._init();

}
使用构造函数模式,构造函数内部调用私有方法_init();
 
  
flow_slide_imgs.prototype = {
_init:
function (options) {

var defaults = {
containerId:
' container ' ,
ImgsWidth:
0.6


};
var opts = util.extend(defaults, options);

this .container = util.$(opts.containerId);
this .imgs = this .container.getElementsByTagName( ' img ' );
this .imgWidth = parseInt(util.getComputedStyle( this .container).width) * opts.ImgsWidth;
this .containerWidth = parseInt(util.getComputedStyle( this .container).width);
this .containerHeight = parseInt(util.getComputedStyle( this .container).height);
this .aveWidth = this .containerWidth / this .imgs.length;
this .newAveWidth = ( this .containerWidth - parseInt( this .imgWidth)) / ( this .imgs.length - 1 );
this .selectedIndex;
this .movePath = 80 ;
this .canLeft = true ;
this .canRight = true ;


this ._setContainerStyle();
this ._setImgsStyle();
this ._bindClickEvent();


},

_init方法中,复制传入的参数对象,并使用extend方法把传入参数与默认参数结合,再以对象属性形式保存。最后调用其他私有函数进行初始化。

 
  
_setContainerStyle: function () {
this .container.style.cssText = ' overflow:hidden; position:relative; ' ;

},

设置容器的样式,由于容器内图片使用绝对定位并改变位置来实现图片的展开和折叠,所以容器设置为相对定位,并且隐藏超出容器的图片。

 
  
_setImgsStyle: function () {

for ( var i = 0 ; i < this .imgs.length; i ++ ) {
this .imgs[i].style.cssText = ' position:absolute; '
+ ' left: ' + i * this .aveWidth + ' px; '
+ ' top:0px; '
+ ' width: ' + this .imgWidth + ' ; '
+ ' height: ' + this .containerHeight + ' px; '
+ ' z-index: ' + i + ' ; '
+ ' display:block ' ;




}

},

获取容器内图片,并批量设置图片样式,aveWidth为图片初始的平均宽度,该数值在_init方法中通过容器宽度除以图片数量得出。以每张图片的索引为值设置图片的层叠级别,这样可以保证由最左边开始,一张图片叠在其右边的图片的上面。由于图片为行内元素,所以再设置其display为block。

 
  
_getSelectedIndex: function (target) {
for ( var i = 0 , len = this .imgs.length; i < len; i ++ ) {
if (target == this .imgs[i]) {
if ( this .selectedIndex && this .selectedIndex < i) {
this .canLeft = true ;
this .canRight = false ;
}
if ( this .selectedIndex && this .selectedIndex > i) {
this .canLeft = false ;
this .canRight = true ;
}
break ;

}
}
return i;
},

获取所选择图片,并且把该图片的索引和之前已打开的图片的索引进行比较,如果所选图片在已打开的图片左边,则图片组只何以向左移动,否则图片只可以向右移动,这样是为了解决鼠标移动过快造成的左边图片和右边图片作相反方向移动的问题。总之,这里保证的所有图片向同一个方向移动。

 
  
_resetImgsSizeAndPos: function (obj, selectedIndex) {


if ( typeof obj.selectedIndex == ' undefined ' ) {
if (parseInt(util.getComputedStyle(obj.imgs[ 1 ]).left) > obj.newAveWidth) {


for ( var i = 1 ; i < obj.imgs.length; i ++ ) {

if (i <= selectedIndex)
obj.imgs[i].style.left
= Math.max(parseInt(obj.imgs[i].style.left) - obj.movePath * i, i * obj.newAveWidth) + ' px ' ;
else
obj.imgs[i].style.left
= Math.min(parseInt(obj.imgs[i].style.left) + obj.movePath * (obj.imgs.length - i), obj.containerWidth - (obj.imgs.length - i) * obj.newAveWidth) + ' px ' ;
}


obj.timeId
= window.setTimeout(arguments.callee, 100 , obj, selectedIndex);
}
if (parseInt(util.getComputedStyle(obj.imgs[ 1 ]).left) == obj.newAveWidth || parseInt(util.getComputedStyle(obj.imgs[ 1 ]).left) == obj.imgWidth) {
obj.selectedIndex
= selectedIndex;
}
}
else if (obj.selectedIndex > selectedIndex) {

if (parseInt(util.getComputedStyle(obj.imgs[selectedIndex + 1 ]).left) < (selectedIndex + 1 ) * obj.newAveWidth + (obj.imgWidth - obj.newAveWidth) && obj.canRight) {

for ( var j = selectedIndex + 1 ; j <= obj.selectedIndex; j ++ ) {

obj.imgs[j].style.left
= Math.min(parseInt(obj.imgs[j].style.left) + obj.movePath, obj.newAveWidth * (j - 1 ) + obj.imgWidth) + ' px ' ;
}


obj.timeId
= window.setTimeout(arguments.callee, 100 , obj, selectedIndex);
}
else {
obj.canLeft
= true ;

obj.selectedIndex
= selectedIndex;

}
}
else if (obj.selectedIndex < selectedIndex) {
if (parseInt(util.getComputedStyle(obj.imgs[selectedIndex]).left) > (selectedIndex) * obj.newAveWidth && obj.canLeft) {

for ( var j = selectedIndex; j > obj.selectedIndex; j -- ) {

obj.imgs[j].style.left
= Math.max(parseInt(obj.imgs[j].style.left) - obj.movePath, j * obj.newAveWidth) + ' px ' ;
}


obj.timeId
= window.setTimeout(arguments.callee, 100 , obj, selectedIndex);
}
else {
obj.canRight
= true ;

obj.selectedIndex
= selectedIndex;

}

}



},

根据 所有图片均未打开(第一次选择图片),已打开图片在所选择图片的前面,已打开图片在所选择图片的后面 这三种情况,图片组作不同方向的运动,通过setTimeout每隔100ms移动一个单位位移。

 
  
_bindClickEvent: function () {
util.addEventHandler(
this .container, ' mouseover ' , ( function (obj) {
return function (eve) {

eve
= eve || window.event;
var target = eve.srcElement || eve.target,
selectedIndex
= obj._getSelectedIndex(target);


obj._resetImgsSizeAndPos(obj, selectedIndex);

}

})(
this ));

}

为容器的mouseover事件绑定事件处理程序,利用事件冒泡在容器的处理程序里产生选中图片时的效果。

这里由于需要为事件处理传递参数,所以利用闭包,使传入的obj对象可访问。鼠标移动到图片上方时,调用上面分析过的resetImgsSizeAndPos方法,根据实际情况让图片作出不同的运动。

 
  
new flow_slide_imgs();

最后是调用方法,这里没有传入参数,则控件里面使用默认值。

完整demo代码:

html: 

ContractedBlock.gifExpandedBlockStart.gifView Code
<div id="container">
<img src="http://images.cnblogs.com/cnblogs_com/Cson/290336/r_cat1.jpg" />
<img src="http://images.cnblogs.com/cnblogs_com/Cson/290336/r_cat2.jpg" />
<img src="http://images.cnblogs.com/cnblogs_com/Cson/290336/r_cat3.jpg" />
<img src="http://images.cnblogs.com/cnblogs_com/Cson/290336/r_cat4.jpg" />
<img src="http://images.cnblogs.com/cnblogs_com/Cson/290336/r_cat5.jpg" />
</div>

css:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
#container { width : 600px ; height : 300px ; background-color : Black ; }
#container img
{ display : none ; }

base.js:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
var util = {
$:
function (sId) { return document.getElementById(sId); },
addEventHandler:
function (elem, type, handler) {
if (elem.addEventListener) {
elem.addEventListener(type, handler,
false );
}
else {
elem.attachEvent(
" on " + type, handler);
}
},
removeEventHandler:
function (elem, type, handler) {
if (elem.removeEventListener) {
elem.removeEventListener(type, handler,
false );
}
else {
elem.detachEvent(
" on " + type, handler);
}
},
getComputedStyle:
function (elem) {
if (elem.currentStyle)
return elem.currentStyle;
else {
return document.defaultView.getComputedStyle(elem, null );
}
},

getElementsByClassName:
function (className, parentElement) {
var elems = (parentElement || document.body).getElementsByTagName( " * " );
var result = [];
for (i = 0 ; j = elems[i]; i ++ ) {
if (( " " + j.className + " " ).indexOf( " " + className + " " ) != - 1 ) {
result.push(j);
}
}
return result;
},
extend:
function (destination, source) {
for ( var name in source) {
destination[name]
= source[name];
}
return destination;

}



};

(
function () {
var st = window.setTimeout;
window.setTimeout
= function (fn, mDelay) {
var t = new Date().getTime();
if ( typeof fn == ' function ' ) {
var args = Array.prototype.slice.call(arguments, 2 );
var f = function () {
args.push(
new Date().getTime() - t - mDelay);
fn.apply(
null , args)
};
return st(f, mDelay);
}
return st(fn, mDelay);
}
})();

flow_slide_imgs.js:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
/*
created by cson
supports ie 6 7 8 firefox and chrome
*/

/* constructor of 'flow images controller' */
var flow_slide_imgs = function (options) {
this ._init();



}
flow_slide_imgs.prototype
= {
/* init container and images and set object's properties */
_init:
function (options) {

var defaults = {
containerId:
' container ' ,
ImgsWidth:
0.6


};
var opts = util.extend(defaults, options);

this .container = util.$(opts.containerId);
this .imgs = this .container.getElementsByTagName( ' img ' );
this .imgWidth = parseInt(util.getComputedStyle( this .container).width) * opts.ImgsWidth;
this .containerWidth = parseInt(util.getComputedStyle( this .container).width);
this .containerHeight = parseInt(util.getComputedStyle( this .container).height);
this .aveWidth = this .containerWidth / this .imgs.length;
this .newAveWidth = ( this .containerWidth - parseInt( this .imgWidth)) / ( this .imgs.length - 1 );
this .selectedIndex;
this .movePath = 80 ;
this .canLeft = true ;
this .canRight = true ;


this ._setContainerStyle();
this ._setImgsStyle();
this ._bindClickEvent();


},
/* set container's style */
_setContainerStyle:
function () {
this .container.style.cssText = ' overflow:hidden; position:relative; ' ;

},
/* set styles of images in container */
_setImgsStyle:
function () {

for ( var i = 0 ; i < this .imgs.length; i ++ ) {
this .imgs[i].style.cssText = ' position:absolute; '
+ ' left: ' + i * this .aveWidth + ' px; '
+ ' top:0px; '
+ ' width: ' + this .imgWidth + ' ; '
+ ' height: ' + this .containerHeight + ' px; '
+ ' z-index: ' + i + ' ; '
+ ' display:block ' ;




}

},
/* get current selected image's index */
_getSelectedIndex:
function (target) {
for ( var i = 0 , len = this .imgs.length; i < len; i ++ ) {
if (target == this .imgs[i]) {
if ( this .selectedIndex && this .selectedIndex < i) {
this .canLeft = true ;
this .canRight = false ;
}
if ( this .selectedIndex && this .selectedIndex > i) {
this .canLeft = false ;
this .canRight = true ;
}
break ;

}
}
return i;
},


/* reset images' size and position for three situation */
_resetImgsSizeAndPos:
function (obj, selectedIndex) {


if ( typeof obj.selectedIndex == ' undefined ' ) {
if (parseInt(util.getComputedStyle(obj.imgs[ 1 ]).left) > obj.newAveWidth) {


for ( var i = 1 ; i < obj.imgs.length; i ++ ) {

if (i <= selectedIndex)
obj.imgs[i].style.left
= Math.max(parseInt(obj.imgs[i].style.left) - obj.movePath * i, i * obj.newAveWidth) + ' px ' ;
else
obj.imgs[i].style.left
= Math.min(parseInt(obj.imgs[i].style.left) + obj.movePath * (obj.imgs.length - i), obj.containerWidth - (obj.imgs.length - i) * obj.newAveWidth) + ' px ' ;
}


obj.timeId
= window.setTimeout(arguments.callee, 100 , obj, selectedIndex);
}
if (parseInt(util.getComputedStyle(obj.imgs[ 1 ]).left) == obj.newAveWidth || parseInt(util.getComputedStyle(obj.imgs[ 1 ]).left) == obj.imgWidth) {
obj.selectedIndex
= selectedIndex;
}
}
else if (obj.selectedIndex > selectedIndex) {

if (parseInt(util.getComputedStyle(obj.imgs[selectedIndex + 1 ]).left) < (selectedIndex + 1 ) * obj.newAveWidth + (obj.imgWidth - obj.newAveWidth) && obj.canRight) {

for ( var j = selectedIndex + 1 ; j <= obj.selectedIndex; j ++ ) {

obj.imgs[j].style.left
= Math.min(parseInt(obj.imgs[j].style.left) + obj.movePath, obj.newAveWidth * (j - 1 ) + obj.imgWidth) + ' px ' ;
}


obj.timeId
= window.setTimeout(arguments.callee, 100 , obj, selectedIndex);
}
else {
obj.canLeft
= true ;

obj.selectedIndex
= selectedIndex;

}
}
else if (obj.selectedIndex < selectedIndex) {
if (parseInt(util.getComputedStyle(obj.imgs[selectedIndex]).left) > (selectedIndex) * obj.newAveWidth && obj.canLeft) {

for ( var j = selectedIndex; j > obj.selectedIndex; j -- ) {

obj.imgs[j].style.left
= Math.max(parseInt(obj.imgs[j].style.left) - obj.movePath, j * obj.newAveWidth) + ' px ' ;
}


obj.timeId
= window.setTimeout(arguments.callee, 100 , obj, selectedIndex);
}
else {
obj.canRight
= true ;

obj.selectedIndex
= selectedIndex;

}

}



},

/* bind handler for mouseover event of images */
_bindClickEvent:
function () {
util.addEventHandler(
this .container, ' mouseover ' , ( function (obj) {
return function (eve) {

eve
= eve || window.event;
var target = eve.srcElement || eve.target,
selectedIndex
= obj._getSelectedIndex(target);


obj._resetImgsSizeAndPos(obj, selectedIndex);

}

})(
this ));

}


}

欢迎转载,请标明出处:http://www.cnblogs.com/Cson/archive/2011/04/03/2004717.html

转载于:https://www.cnblogs.com/Cson/archive/2011/04/03/2004717.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: protobuf是一种语言无关的数据序列化格式,可以将结构化数据以二进制形式进行存储、传输和解析。相比其他序列化格式(如JSON和XML),protobuf具有更高的效率和更小的存储空间,特别适用于性能要求较高的场景。 CSON是一种基于文本的数据交换格式,它的语法和JSON类似,但更加简洁易读。CSON可以直接嵌入到许多编程语言中,而无需额外的解析器或库。相比JSON,CSON有更好的人机可读性,可以更快地编写和解析。在一些开发工具中,如Atom编辑器,CSON被广泛用于配置文件。 当我们使用protobuf和CSON时,两者的作用是不同的。protobuf主要用于高效的数据存储和传输,主要用于网络通信和持久化存储。它定义了用于描述结构化数据的消息格式,并生成相应的编解码代码。protobuf允许我们使用预定义的消息结构定义数据模型,并将其序列化为二进制数据进行传输或存储。在接收端,我们可以将二进制数据反序列化为原始的消息结构,以进行后续处理。 CSON则更适用于配置文件和简单数据的存储和交换。与JSON相比,CSON的语法更简洁易读,可以更方便地进行人工编辑和修改。在开发过程中,我们可以使用CSON格式的配置文件来定义应用程序的设置和参数,以及其他需要在运行时进行调整的数据。CSON可以与各种编程语言一起使用,通过相应的解析库来读取和写入CSON数据。 综上所述,protobuf和CSON都是用于数据交换和存储的格式,但其使用场景和特点有所不同。protobuf适合高效的网络通信和持久化存储,而CSON则适用于配置文件和简单数据的存储和交换。 ### 回答2: protobuf cson 是 Google 开发的一种数据序列化格式,可以用于不同编程语言之间的数据交换。cson 是 CSN(CoffeeScript Object Notation)的缩写,它是一种类似于 JSON 的数据格式,但具有更简洁和易读的语法。 protobuf cson 结合了 Protocol Buffers(一种用于结构化数据的语言无关、平台无关、可扩展的序列化格式)和 cson 的优势,既可以确定数据结构,又可以通过人类可读的方式来表示数据。相比于 JSON,protobuf cson 使用更少的字符来表示相同的数据结构,因此也更加紧凑和高效。 使用 protobuf cson,开发者可以根据预先定义好的消息结构来序列化和反序列化数据。通过定义消息类型和字段,我们可以精确控制所要传输的数据结构,在不同语言中实现数据的互相转换。同时,protobuf cson 还支持扩展和向后兼容性,可以轻松地向已有的消息类型添加新的字段。 protobuf cson 在分布式系统、微服务架构以及网络通信中广泛应用。它的高效和灵活性使得数据的传输和解析更加方便和高效。此外,由于具备易读的特性,一些配置文件和参数文件也可以使用 protobuf cson 进行存储和传输。 总而言之,protobuf cson 是一种强大的数据序列化格式,它兼具 Protocol Buffers 和 cson 的优势。通过结构化和紧凑的表示,protobuf cson 提供了高效的数据传输和解析方式,广泛应用于不同领域和语言环境中。 ### 回答3: protobuf是一种数据序列化格式,用于将结构化数据转化为可传输和存储的二进制格式。而CSON则是一种用于存储和表示数据的文本格式,类似于JSON,但更接近于CoffeeScript语法。 protobuf和CSON在功能和用途上有一些差异。protobuf适合用于高效地序列化和反序列化数据,并且可以在多种编程语言之间进行数据交换。它使用二进制格式,因此在数据传输和存储方面更高效,尤其是对于大量数据和复杂结构的数据。protobuf还提供了强大的扩展和版本控制机制,使得在不同版本之间进行数据兼容性处理更加方便。 CSON则更加适用于人类可读和可编辑的数据表示。它使用文本格式并支持类似于CoffeeScript的语法,因此更加容易阅读和理解。与JSON相比,CSON提供了一些额外的功能,比如支持注释和多行字符串。但是,CSON相对于protobuf而言在性能上差一些,因为它需要将文本转换为内部数据结构,并且在解析和生成过程中需要进行额外的处理。 总的来说,如果需要高效的数据传输和存储,或者需要跨多种编程语言进行数据交换,protobuf是更好的选择。而如果需要人类可读和可编辑的数据表示,或者对数据格式有更高的灵活性要求,使用CSON可能更合适。但是,具体使用哪种格式还是要根据具体的应用场景和需求来决定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值