roundabout效果
效果就像优酷综艺频道页面的图片轮播。
本屌之前做过这个roundabout,参见仿优酷频道首页的图片切换效果,不过用的是类似jquery的库做的。尽管js代码不到200行,但还是显得有点复杂。于是乎,本屌盘算着可不可以用更少的代码完成这个效果。
顺便说一下,如果有读者想造轮子,可以直接看优酷的js代码,基本上都没压缩,封装这个效果的代码在posterTvGrid.js
下面是本屌做出来的效果
http://v.youku.com/v_show/id_XMTM1ODk4NDQyNA==.html
要求
点击左右箭头,图片滚动
点击下面图片索引,如果点击的图片是当前图片或与当前图片相邻的图片,则图片滚动;否则,所有图片先变小,然后点击的图片和与之相邻的图片,在相应位置动态变大。
代码尽可能少,尽可能清晰
布局
<div id='wrap' ms-controller='roundabout'>
<div id='roundabout'>
<ul>
<li ms-repeat-img='img_list' ms-attr-id='img{{$index}}'>
<img ms-attr-src="img/{{img}}.jpeg">
</li>
</ul>
</div>
</div>
图片的位置有2种情况:
不可见,即不是前面的3张图片,这里类名
.hide
.hide {
width: 530px;
height: 100px;
opacity: 0;
z-index: 0;
margin-top: 0;
left: -530px;
}
可见的3张图片,按位置具体可分为
.left
,.middle
,.right
.middle {
width: 640px;
height: 270px;
opacity: 1;
z-index: 2;
margin-top: 0;
left: 275px;
}
.left {
width: 530px;
height: 224px;
opacity: 0.4;
z-index: 1;
margin-top: 23px;
left: 0;
}
.right {
width: 530px;
height: 224px;
opacity: 0.4;
z-index: 1;
margin-top: 23px;
left: 660px;
}
每个类的6个属性都是和图片尺寸(640*270)配合好的,使得动画很自然。当然后面会用到css3 animation,使每张图片的这6个属性进行相应的变化。
下面把上面类添加到相应图片上
var roundabout=avalon.define({
$id:'roundabout',
img_list:[],
cur:0,//当前页
...
});
cur
相对于指针,表示当前中间(可见范围最大)图片是图片列表里的哪张图片,所以会有(从左向右看)
cur
=>.middle
cur+1
=>.right
cur-1
=>.left
其他
=>.hide
插值表达式中的逻辑运算符
这里就要把逻辑运算符用到插值表达式里
<div id='roundabout'>
<ul>
<li ms-repeat-img='img_list' ms-attr-id='img{{$index}}'
ms-class-hide='($index<cur-1&&(cur!=img_list.size()-1||$index!=0))||
($index>cur+1&&(cur!=0||$index!=img_list.size()-1))'
ms-class-left='$index==cur-1||(cur==0&&$index==img_list.size()-1)'
ms-class-right='$index==cur+1||(cur==img_list.size()-1&&$index==0)'
ms-class-middle='$index==cur' class='animated'>
<img ms-attr-src="img/{{img}}.jpeg">
</li>
</ul>
</div>
解释下ms-class-middle='$index==cur'
这个很简单,指针的当前位置,添加.middle
.
ms-class-left='$index==cur-1||(cur==0&&$index==img_list.size()-1)'
后面部分表示,如果指针在第一张图片那里,就在最后一张图片上添加.left
.
ms-class-right='$index==cur+1||(cur==img_list.size()-1&&$index==0)'
和上面类似,后面部分表示,如果指针在最后一张图片那里,就在第一张图片上添加.right
.
ms-class-hide='($index<cur-1&&(cur!=img_list.size()-1||$index!=0))||($index>cur+1&&(cur!=0||$index!=img_list.size()-1))'
由两个大或(||)
组成
前面部分$index<cur-1&&(cur!=img_list.size()-1||$index!=0)
表示在cur-1
(左边的可见)图片以左的图片,都会添加.hide
隐藏,除开一种情况,当前指针在最后一张图片那里时,图片列表中的第一张图片不能添加.hide
,因为它将被添加.right
.
这里利用了||运算符
的特点,如果第一个条件满足的话,就不会去判定第二个条件;第一个条件不满足时,才会去判定第二个条件。
后面部分$index>cur+1&&(cur!=0||$index!=img_list.size()-1)
表示在cur+1
(右边的可见)图片以右的图片,都会添加.hide
隐藏,除了当前指针在第一张图片那里时,图片列表中的最后一张图片不能添加.hide
,因为它将被添加.left
.
实际上,用离散数学里的非(p且q)=非p或非q
就很好想了,除开已经添加了.left
,.middle
,.right
的图片,剩下的就得添加.hide
,$index>cur+1
和$index<cur-1
可以保证$index!=cur
.
然后是排除.left
,满足.left
的条件是$index==cur-1||(cur==0&&$index==img_list.size()-1)
,它的否定是$index!=cur-1&&(cur!=0||$index!=img_list.size()-1)
,这就和添加.hide
的条件的左边部分一样了。
排除.right
也是类似的。
把这两个部分组合起来就可以保证.left,.middle,.right,.hide这4个类之间是互斥的
。
当然也可以利用css优先级
,让.left
,.middle
,.right
类的优先级高于.hide
,这样添加.hide
的判定条件会简单很多。为了严谨些,就没有用这种方式。
圆点序列
<div id='jump'>
<ul>
<li ms-repeat='img_list' ms-class-on='cur==$index'></li>
</ul>
</div>
cur==$index
让'亮'的圆点和当前指针同步。
到这里,任意改变roundabout.cur=?
都可以呈现roundabout布局。
图片滚动
定义css3 animation
滚动过程中,要滚动图片有4种动画状态,以向右滚动为例
左边可见的图片的上(左)一张图片,
不可见
=>在可见部分左边,部分可见
原来左边可见的图片,
在可见部分左边,部分可见
=>中间,全部可见
原来中间全部可见的图片,
中间,全部可见
=>在可见部分右边,部分可见
原来右边可见的图片,
在可见部分右边,部分可见
=>不可见
这里用css3 animation
@keyframes to-right1 {//向右滚动
0% {
width: 530px;
height: 100px;
opacity: 0;
z-index: 0;
margin-top: 85px;
left: -530px;
}
100% {
width: 530px;
height: 224px;
opacity: 0.4;
z-index: 1;
margin-top: 23px;
left: 0;
}
}
@keyframes to-right2 {
0% {
width: 530px;
height: 224px;
opacity: 0.4;
z-index: 1;
margin-top: 23px;
left: 0;
}
100% {
width: 640px;
height: 270px;
opacity: 1;
z-index: 2;
margin-top: 0;
left: 275px;
}
}
@keyframes to-right3 {
0% {
width: 640px;
height: 270px;
opacity: 1;
z-index: 2;
margin-top: 0;
left: 275px;
}
100% {
width: 530px;
height: 224px;
opacity: 0.4;
z-index: 1;
margin-top: 23px;
left: 660px;
}
}
@keyframes to-right4 {
0% {
width: 530px;
height: 224px;
opacity: 0.4;
z-index: 1;
margin-top: 23px;
left: 660px;
}
100% {
width: 530px;
height: 100px;
opacity: 0;
z-index: 0;
margin-top: 85px;
left: 1190px;
}
}
...
可以看到,动画无非是在.hide
,.left
,.middle
,.right
这4个状态间切换。
@keyframes to-right1 {//向右滚动
0% {
//.hide
}
100% {
//.left
}
}
@keyframes to-right2{
0% {
//.left
}
100% {
//.middle
}
}
@keyframes to-right3{
0% {
//middle
}
100% {
//right
}
}
@keyframes to-right4{
0% {
//right
}
100% {
//hide1
}
}
...
为了方便编码,用less
.state(@width,@height,@opacity,@z-index,@margin-top,@left){
width: @width;
height: @height;
opacity: @opacity;
z-index: @z-index;
margin-top: @margin-top;
left:@left;
}
.middle(){
.state(640px,270px,1,2,0,275px);
}
.left(){
.state(530px,224px,0.4,1,23px,0);
}
.right(){
.state(530px,224px,0.4,1,23px,660px);
}
.hide(){
.state(530px,100px,0,0,85px,-530px);
}
.hide1(){
.state(530px,100px,0,0,85px,1190px);
}
.middle{
.middle();
}
.left{
.left();
}
.right{
.right();
}
.hide{
.hide();
}
@keyframes to-right1{//向右滚动
0% {
.hide();
}
100% {
.left();
}
}
@keyframes to-right2{
0% {
.left();
}
100% {
.middle();
}
}
@keyframes to-right3{
0% {
.middle();
}
100% {
.right();
}
}
@keyframes to-right4{
0% {
.right();
}
100% {
.hide1();
}
}
...
点击左右箭头,图片滚动
var roundabout=avalon.define({
$id:'roundabout',
img_list:[],
cur:0,//当前页
jump:function(i,dir){//dir:滚动方向
roundabout.cur=i;
}
});
<div id='wrap' ms-controller='roundabout'>
<div id='controls'>
<a class='left_arrow' href="javascript:;"
ms-click='jump(cur==0?img_list.size()-1:cur-1,1)'></a>
<a class='right_arrow' href="javascript:;"
ms-click='jump(cur==img_list.size()-1?0:cur+1,2)'></a>
</div>
...
</div>
jump
方法的dir参数后面会用到。
这里还没有添加动画类,只能进行没有动画的滚动。
添加动画
//所有的动画类
var animate_class='to-right1 to-right2 to-right3 to-right4 to-left1 to-left2 to-left3 to-left4';
...
jump:function(i,dir){
if(dir==1){//向右滚 cur-1
avalon($('img'+prev(i))).removeClass(animate_class).addClass('to-right1');
avalon($('img'+i)).removeClass(animate_class).addClass('to-right2');
avalon($('img'+next(i))).removeClass(animate_class).addClass('to-right3');
avalon($('img'+next(next(i)))).removeClass(animate_class).addClass('to-right4');
}else{//向左滚 cur+1
avalon($('img'+next(i))).removeClass(animate_class).addClass('to-left1');
avalon($('img'+i)).removeClass(animate_class).addClass('to-left2');
avalon($('img'+prev(i))).removeClass(animate_class).addClass('to-left3');
avalon($('img'+prev(prev(i)))).removeClass(animate_class).addClass('to-left4');
}
roundabout.cur=i;
}
...
function prev(now){//上一页
return now==0?roundabout.img_list.size()-1:now-1;
}
function next(now){//下一页
return now==roundabout.img_list.size()-1?0:now+1;
}
几点说明
这里的
removeClass
方法和jquery中的一样,当传入参数像上面animate_class变量
,多个类以空格分开时,对目标删除多个类(如果有的话)。prev
,next
方法用来得到上一张图片和下一张图片的在图片列表中的索引.注意next(next(i))不等于next(i+1).添加动画类之前,要先删除所有可能存在的动画类。
点击圆点,图片滚动
和点击左右箭头,图片滚动的动画不一样,这里对目标图片及其左右图片是一个从小变大的动画效果。
.state(@width,@height,@opacity,@z-index,@margin-top,@left){
width: @width;
height: @height;
opacity: @opacity;
z-index: @z-index;
margin-top: @margin-top;
left:@left;
}
.jump-state(){
.state(0,0,0,0,135px,585px);
}
@keyframes jump-prev{//变小->左边图片
0% {
.jump-state();
}
100% {
.left();
}
}
@keyframes jump-middle{//变小->中间图片
0% {
.jump-state();
}
100% {
.middle();
}
}
@keyframes jump-next{//变小->右边图片
0% {
.jump-state();
}
100% {
.right();
}
}
下面对圆点绑定点击事件
<div id='jump'>
<ul>
<li ms-repeat='img_list' ms-class-on='cur==$index' ms-click='spec_jump($index)'></li>
</ul>
</div>
spec_jump:function(i){
var cur=roundabout.cur;
if(cur-prev(i)==0||cur-next(i)==0){//如果点击的图片是当前图片或当前图片的相邻图片
var dir=1;//确定滚动方向
if(cur-prev(i)==0)
dir=2;
roundabout.jump(i,dir);
}else{
roundabout.cur=i;
avalon($('img'+prev(i))).removeClass(animate_class).addClass('jump-prev');
avalon($('img'+i)).removeClass(animate_class).addClass('jump-middle');
avalon($('img'+next(i))).removeClass(animate_class).addClass('jump-next');
}
}
这里会添加jump-prev
,jump-middle
,jump-next
类,所以前面的animate_class变量
也要加上这3个类。
后记
js代码不超过50行,当然css代码多点,不过用less
写的话,编程体验很好
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。