效果流--动态切换图片/内容栏
前言 : 有朋友看了我们的99分, 我处理的动画效果后觉得很赞, 想用于他们的平台上, 用来显示图片和内容. 然而我的那个平台整个就是一个canvas, 用于他的部分显然不适合.
但是用JQ 就能够很容易实现了. 只需要找到位置, 然后使用JQ的animate, 然后对他做一系列事件处理, 就ok了. 恩, 原理如此简单(当然做为dom 本来就没canvas 处理那么复杂, 虽然原理是差不多的, 但是canvas还有更多的绘制计算在内).
...
后来一想, 太不负责了, 就这样告诉人家, 其实做为DEMO 可以, 做为产品, 这就是大大的不妥了. 怎么填充数据? 怎么切换数据? 都木有哇.
所以经我这样一想, 这玩意立马就复杂了. 于是就有了这样一个相对折腾的东西, 一个封装好了的组件
不多说, 看代码 (他需要引用jq)
1 <!doctype html> 2 <html> 3 <head> 4 <title>move</title> 5 <meta charset="utf-8" /> 6 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> 7 </head> 8 <body> 9 <div id="page"> 10 <div id="header" class="header"> 11 <div class="w800 center"> 12 </div> 13 </div> 14 <div id="content" class="content w800 center"> 15 我自己本身的是用canvas的, 所以写的算法是自己的, 这里如果仅仅是dom的话, 我们可以简单的用jq来实现. <br /> 16 这里我实现了一个可以拓展的框架, 应该对你可以用有. 他可以适合很多应用和变化的场景. 包括修改等. 17 <br /> 18 <style> 19 .show-0{width:350px;height:250px;border:1px red solid;position:relative;} 20 .show-0 .s1{position:absolute;width:70px;height:110px;border:1px red solid;background:#fff;} 21 </style> 22 <div id="test" class="show-0"> 23 <div class="s1"> 0-1</div> 24 <div class="s1"> 0-2</div> 25 <div class="s1"> 0-3</div> 26 <div class="s1"> 0-4</div> 27 <div class="s1"> 0-5</div> 28 <div class="s1"> 0-6</div> 29 <div class="s1"> 0-7</div> 30 <div class="s1"> 0-8</div> 31 <div class="s1"> 1-1</div> 32 <div class="s1"> 1-2</div> 33 <div class="s1"> 1-3</div> 34 <div class="s1"> 1-4</div> 35 <div class="s1"> 1-5</div> 36 <div class="s1"> 1-6</div> 37 <div class="s1"> 1-7</div> 38 <div class="s1"> 1-8</div> 39 <div class="s1"> 2-1</div> 40 <div class="s1"> 2-2</div> 41 <div class="s1"> 2-3</div> 42 <div class="s1"> 2-4</div> 43 <div class="s1"> 2-5</div> 44 <div class="s1"> 2-6</div> 45 <div class="s1"> 2-7</div> 46 <div class="s1"> 2-8</div> 47 </div> 48 </div> 49 </div> 50 <script type="text/javascript"> 51 (function(){ 52 /* 53 * author : hehe123 (Jerrod.zhou) 54 * mail : mag.zhoujie@gmail.com 55 */ 56 var plugin_divMoive = { 57 methods: { 58 nextShow: function(elms, data, callback, n){ 59 var rec, i = 0, len = elms.length; 60 rec = setInterval(function(){ 61 elms[i].show().animate({ 62 left: data.sidePos[i].l, 63 top: data.sidePos[i].t, 64 opacity: 1 65 }, 300); 66 (n && i === n && callback) && callback(); 67 i++; 68 if (i >= len) { 69 clearInterval(rec); 70 (!n && callback) && callback(); 71 } 72 }, 150); 73 }, 74 prevHide: function(elms, data, callback, n){ 75 var rec, i = 0, len = elms.length; 76 rec = setInterval(function(){ 77 elms[i].show().animate({ 78 left: data.centerPos[0], 79 top: data.centerPos[1], 80 opacity: 0.5 81 }, 300, function(){ 82 $(this).hide(); 83 }); 84 (n && i === n && callback) && callback(); 85 i++; 86 if (i >= len) { 87 clearInterval(rec); 88 (!n && callback) && callback(); 89 } 90 }, 150); 91 }, 92 run: function(){ 93 var DM = plugin_divMoive, Mds = DM.methods; 94 return function(){ 95 var P = this, status = P.status, elms = P.elms, data = P.data, childs = elms.childs, i = data.showClipFrameIdx, rec = data.rec, rTime = 0; 96 if (status.isMoving) { 97 return; 98 } 99 status.isMoving = true; 100 status.isOnParent = false; 101 function mouseout(){ 102 status.isMouseover = false; 103 status.isMouseout = true; 104 data.mouseOutRec = setTimeout(function(){ 105 status.isMouseout && P.goon(); 106 if(!status.isOnParent){ 107 status.isOnParent = true; 108 P.onover && P.onover(P); 109 } 110 }, 1); 111 } 112 function mouseover(){ 113 status.isMouseover = true; 114 status.isMouseout = false; 115 data.mouseOverRec = setTimeout(function(){ 116 status.isMouseover && P.pause(); 117 status.isOnParent = false; 118 P.onout && P.onout(P); 119 }, 1); 120 } 121 elms.parent.unbind('mouseover', mouseover).bind('mousemove', mouseover).unbind('mouseout', mouseout).bind('mouseout', mouseout) 122 Mds.nextShow(data.showClipFrameArr[i], data, function(){ 123 P.onshow && P.onshow(P); 124 }); 125 data.rec = setInterval(function(){ 126 if (status.isPause || status.isDeforming) { 127 return; 128 } 129 if ((rTime + 1) % P.time === 0) { 130 status.isDeforming = true; 131 i = data.showClipFrameIdx; 132 Mds.prevHide(data.showClipFrameArr[i], data, function(){ 133 P.onhide && P.onhide(P); 134 i = i + 1 >= data.showClipFrameLength ? 0 : i + 1; 135 Mds.nextShow(data.showClipFrameArr[i], data, function(){ 136 P.onshow && P.onshow(P); 137 data.showClipFrameIdx = i; 138 status.isDeforming = false; 139 }); 140 }, 5); 141 } 142 rTime++; 143 rTime >= 1000 && (rTime = 0); 144 }, 1000); 145 }; 146 }, 147 switcher : function(){ 148 var DM = plugin_divMoive, Mds = DM.methods; 149 return function(n){ 150 var P = this, status = P.status, elms = P.elms, data = P.data, childs = elms.childs, i = data.showClipFrameIdx; 151 if(status.isDeforming){ 152 return; 153 } 154 status.isPause = true; 155 Mds.prevHide(data.showClipFrameArr[i], data, function(){ 156 P.onhide && P.onhide(P); 157 i = i + 1 >= data.showClipFrameLength ? 0 : i + 1; 158 Mds.nextShow(data.showClipFrameArr[n], data, function(){ 159 P.onshow && P.onshow(P); 160 data.showClipFrameIdx = n; 161 status.isDeforming = false; 162 status.isPause = false; 163 }); 164 }, 5); 165 }; 166 }, 167 stop: function(){ 168 var DM = plugin_divMoive, Mds = DM.methods; 169 return function(){ 170 var P = this, status = P.status, elms = P.elms, data = P.data, rec = data.rec; 171 clearInterval(data.rec); 172 status.isMoving = false; 173 }; 174 }, 175 pause: function(){ 176 return function(callback){ 177 var P = this, status = P.status; 178 status.isPause = true; 179 callback && callback(P); 180 } 181 }, 182 goon: function(){ 183 return function(callback){ 184 var P = this, status = P.status; 185 status.isPause = false; 186 callback && callback(P); 187 } 188 } 189 }, 190 init: function(opts){ 191 var j = 0, z = 0, P = plugin_divMoive, methods = P.methods, data = new Object(), elms = { 192 parent: opts.parent, 193 childs: opts.childs 194 }, run; 195 data.sidePos = []; 196 data.centerPos = [(opts.iWidth - opts.clipWidth) / 2, (opts.iHeight - opts.clipHeight) / 2]; 197 data.properties = { 198 iWidth: opts.iWidth, 199 iHeight: opts.iHeight, 200 iPaddingTop: opts.iPaddingTop, 201 iPaddingLeft: opts.iPaddingLeft, 202 clipWidth: opts.clipWidth, 203 clipHeight: opts.clipHeight, 204 clipMarginRight: opts.clipMarginRight, 205 clipMarginBottom: opts.clipMarginBottom, 206 rows: opts.rows, 207 cols: opts.cols, 208 time: opts.time 209 }; 210 data.showClipElmsNums = opts.rows * opts.cols; 211 data.showClipFrameLength = Math.floor((opts.childs.length + 1) / data.showClipElmsNums); 212 data.showClipFrameArr = function(){ 213 var arr = [], i = -1, len = data.showClipFrameLength - 1; 214 for (; i++ < len; arr[i] = []); 215 return arr; 216 }(); 217 data.showClipFrameIdx = 0; 218 opts.parent.css('position', 'relative'); 219 opts.childs.each(function(i){ 220 data.sidePos.push({ 221 i: i, 222 w: opts.clipWidth, 223 h: opts.clipHeight, 224 l: opts.iPaddingLeft + (i % opts.cols) * (opts.clipWidth + opts.clipMarginRight), 225 t: opts.iPaddingTop + j * (opts.clipHeight + opts.clipMarginBottom) 226 }); 227 $(this).hide().css({ 228 position: 'absolute', 229 left: data.centerPos[0], 230 top: data.centerPos[1], 231 opacity: 0.5 232 }); 233 data.showClipFrameArr[z].push($(this)); 234 (i + 1) % data.showClipElmsNums === 0 && (z++); 235 i % opts.cols === (opts.cols - 1) && (j++); 236 j >= opts.rows && (j = 0); 237 }); 238 return { 239 status: { 240 isMoving: false, 241 isDeforming: false, 242 isPause: false, 243 isMouseover: false, 244 isMouseout: true, 245 isOnParent: false 246 }, 247 elms: elms, 248 data: data, 249 time: opts.time, 250 onshow: opts.onshow || null, 251 onhide: opts.onhide || null, 252 run: methods.run(), 253 stop: methods.stop(), 254 pause: methods.pause(), 255 goon: methods.goon(), 256 switcher: methods.switcher(), 257 onover: opts.onmouseover || null, 258 onout: opts.onmouseout || null 259 }; 260 } 261 }; 262 263 var n0 = plugin_divMoive.init({ 264 parent : $('#test'), 265 childs : $('#test > .s1'), 266 iWidth : $('#test').width(), 267 iHeight : $('#test').height(), 268 iPaddingTop : 10, 269 iPaddingLeft : 10, 270 clipWidth : $('#test > .s1').width(), 271 clipHeight : $('#test > .s1').height(), 272 clipMarginRight : 15, 273 clipMarginBottom : 10, 274 rows : 2, 275 cols : 4, 276 time : 4 277 }); 278 n0.run(); 279 })(); 280 </script> 281 </body> 282 </html>
然后, 下面是该组件的一些说明:
/*
* init 的必选:
* parent : 父级框
* child : 需要移动的子集
* iWidth : 父级的宽
* iHeight : 父级的高
* iPaddingTop : 父级内上边距
* iPaddingLeft : 父级内左边距
* clipWidth : 子集个体宽
* clipHeight : 子集个体高
* clipMarginRight : 子集右边距
* clipMarginBottom : 子集下边距
* rows : 行数 (子集排成的行数)
* cols : 列数 (子集排成的列数)
* time : 停留时间
*
* 可选部分:
* onshow : 每个集合显示完全后的 callback
* 如 onshow:function(O){ ....}
* O 包含整个返回的object部分
* onhide : 每个集合隐藏完全后的 callback
用法如上.
onover : 当鼠标停留在父级上的 callback. 用法如上
onout : 当鼠标离开在父级上的 callback. 用法如上
*/
/*
* 返回的oject
* status : 状态集合, 有
* isMoving: 是否动画已经开始,
isDeforming: 是否正在变形,
isPause: 是否停顿,
isMouseover: 是否鼠标父级上,
isMouseout: 是否鼠标离开父级,
isOnParent: 是否第一次鼠标在父级上
* elms : 元素列表, 主要有两种
* parent: 父级元素
childs: 子级元素
* data : 动态的记录数据
* sidePos : 数组, 记录每次显示时的元素位置
* centerPos : 数组, 记录中心点的位置数据
* properties : 对象, 记录 init 的必须部分参数数据
* showClipElmsNums: 记录每次显示的元素个数
* showClipFrameLength: 记录总共分几页显示数据 (如,每页8个元素, 24个元素就3页)
* ** showClipFrameArr: 每页的分类数组, 如果想修改某页某个元素, 就得依托他.
* showClipFrameIdx: 当前显示到了第几页
* rec : setInterval的句柄
* time : 同init里的time. 停留时间. 也可以修改.
* onshow : 同init里的onshow, 如果有, 则在该页子集显示时触发,
onhide : 同init里的onhide, 如果有, 则在该页子集隐藏时触发,
run : 整个方法类的启动
stop : 整个方法类的停止
pause : 整个方法类的暂停 (在mouseover, mouseout 时也触发他)
goon : 整个方法类的继续运行
switcher : 从当前页跳到某一页
onover : 同init里的onover, 如果有, 则在鼠标在父级上时触发,
onout : 同init里的onout, 如果有, 则在鼠标离开父级上时触发
*/
因为有的pause, stop, goon, 也有了 onshow, onhide, 特别是 switcher (switcher可以帮你实现如果你想要用如
标红部分的切换效果) 等等操作, 甚至可以取到你想要修改的某个元素, 所以基本上, 他的功能是完善的.
ok, 其实他还可以更完善... 但是, 为了一个这样小小的效果堆上这么一些代码我觉得已经够多了(虽然他满足了某一方面的通用性)
以后有机会再修改吧.
By hehe123.