分享一款基于jqery的带3D切换效果的图片展示
先看效果:在线演示。
这个效果并不是我想出来的,我只是对某个开源的flash图片展示(请原谅我并不知道原作的链接……)使用js重写罢了。
起因是,我所在学校的网站(相思湖网站)要进行改版,其中各专题首页需要一个图片展示。某成员找到了一个带3D切换效果的图片展示,可惜是flash做的,并且在使用的过程中有一个问题,如果图片的宽高与原始定义的不同,就会出现一个固定的白框。
当时我的第一反应就是为什么要flash?难道js做不到么?话虽如此,但如果可以改改代码就能解决的话,倒也省事。终归我过于乐观了,尽管as和js是近亲,我却总抓不住问题的关键所在,一部分是因为对flash的不熟悉,令一部分也因为那as代码写得也够凌乱的。总之我决定了要用js重写。
仔细想想这个效果并不很难实现,借助jquery的animation可以轻松实现节点元素的各种动画,唯一的难点是确定图片的位置而已了。
我是利用等比对折来确定图片的位置:
假设整个框架的长度是W,高度是H,图片的长为w,高为h。那么居中的图片的top为(H - h) / 2,left为(W - w) / 2,旁边图片的计算方法类同。
源代码:
js
1 /* 2 * xsh slider for jquery 3 * By: QiuXiang, qiuxiang55aa@gmail.com 4 * Used In: http://xsh.gxun.edu.cn 5 * 6 * Copyright 2012, XSH 7 * Free to use and abuse under the MIT license. 8 * http://www.opensource.org/licenses/mit-license.php 9 */ 10 (function($){ 11 $.fn.xsh_slider = function(options){ 12 var opts = $.extend({}, $.fn.xsh_slider.defawrapts, options); 13 var $this = $(this); 14 var wrap = $('ul', $this); 15 var imgs = []; 16 var current = 1; 17 var pre_img; 18 var cur_img; 19 var next_img; 20 var timeout; 21 22 init(); 23 24 function pre() 25 { 26 unbind_click(); 27 28 next_img.li.removeClass('next_img'); 29 cur_img.li.removeClass('cur_img'); 30 pre_img.li.removeClass('pre_img'); 31 32 current = (current == 0 ? imgs.length - 1 : current - 1); 33 var pre_i = (current == 0 ? imgs.length - 1 : current - 1); 34 var _next_img = next_img; 35 next_img = cur_img; 36 cur_img = pre_img; 37 pre_img = imgs[pre_i]; 38 39 next_img.li.addClass('next_img'); 40 cur_img.li.addClass('cur_img'); 41 pre_img.li.addClass('pre_img'); 42 43 // 动画切换 44 next_hide(_next_img); 45 goto_next(next_img); 46 goto_cur(cur_img); 47 pre_init(pre_img); 48 goto_pre(pre_img); 49 50 alt_hide(next_img); 51 alt_show(cur_img); 52 53 bind_click(); 54 timeout_reset(); 55 } 56 57 // 切换下一张图片 58 function next() 59 { 60 unbind_click(); 61 62 pre_img.li.removeClass('pre_img'); 63 cur_img.li.removeClass('cur_img'); 64 next_img.li.removeClass('next_img'); 65 66 current = ((current == imgs.length - 1) ? 0 : current + 1); 67 var next_i = (current == imgs.length - 1) ? 0 : current + 1; 68 var _pre_img = pre_img; 69 pre_img = cur_img; 70 cur_img = next_img; 71 next_img = imgs[next_i]; 72 73 pre_img.li.addClass('pre_img'); 74 cur_img.li.addClass('cur_img'); 75 next_img.li.addClass('next_img'); 76 77 // 动画切换 78 pre_hide(_pre_img); 79 goto_pre(pre_img); 80 goto_cur(cur_img); 81 next_init(next_img); 82 goto_next(next_img); 83 84 alt_hide(pre_img); 85 alt_show(cur_img); 86 87 bind_click(); 88 timeout_reset(); 89 } 90 91 // pre_img 的消逝 92 function pre_hide(img) 93 { 94 img.li.animate({ 95 width: 0, 96 height: 0, 97 left: 0, 98 top: opts.height / 2, 99 opacity: 0 100 }, { 101 duration: opts.speed, 102 easing: 'easeOutExpo', 103 queue: false 104 }); 105 } 106 107 // next_img 的消逝 108 function next_hide(img) 109 { 110 img.li.animate({ 111 width: 0, 112 height: 0, 113 left: opts.width, 114 top: opts.height / 2, 115 opacity: 0 116 }, { 117 duration: opts.speed, 118 easing: 'easeOutExpo', 119 queue: false 120 }); 121 } 122 123 // 切换到 pre_img 124 function goto_pre(img) 125 { 126 img.li.animate({ 127 width: img.pre.width, 128 height: img.pre.height, 129 left: img.pre.left, 130 top: img.pre.top, 131 opacity: 1 132 }, { 133 duration: opts.speed, 134 easing: 'easeOutExpo', 135 queue: false 136 }); 137 } 138 139 // 切换到 cur_img 140 function goto_cur(img) 141 { 142 img.li.animate({ 143 width: img.center.width, 144 height: img.center.height, 145 left: img.center.left, 146 top: img.center.top, 147 opacity: 1 148 }, { 149 duration: opts.speed, 150 easing: 'easeOutExpo', 151 queue: false 152 }); 153 } 154 155 // 切换到 next_img 156 function goto_next(img) 157 { 158 img.li.animate({ 159 width: img.next.width, 160 height: img.next.height, 161 left: img.next.left, 162 top: img.next.top, 163 opacity: 1 164 }, { 165 duration: opts.speed, 166 easing: 'easeOutExpo', 167 queue: false 168 }); 169 } 170 171 // 绑定图片的点击切换事件 172 function bind_click() 173 { 174 $('.pre_img', $this).click(function(){ 175 pre(); 176 return false; 177 }); 178 $('.next_img', $this).click(function(){ 179 next(); 180 return false; 181 }); 182 } 183 184 // 取消绑定图片的点击切换事件 185 function unbind_click() 186 { 187 $('.pre_img').unbind(); 188 $('.next_img').unbind(); 189 } 190 191 // 重置自动播放 192 function timeout_reset() 193 { 194 clearInterval(timeout); 195 auto_play(); 196 } 197 198 // 显示图片说明 199 function alt_show(img) 200 { 201 if (img.div.text() != '') 202 img.div.css({'display': 'block'}); 203 } 204 205 // 隐藏图片说明 206 function alt_hide(img) 207 { 208 img.div.css({'display': 'none'}); 209 } 210 211 // 创建图片切换按钮 212 function btn_create() 213 { 214 wrap.append('<div class="btn_pre"><a>' + opts.pre_text + '</a></div>'); 215 wrap.append('<div class="btn_next"><a>' + opts.next_text + '</a></div>'); 216 217 var btn_pre = $('.btn_pre', $this); 218 var btn_next = $('.btn_next', $this); 219 220 btn_pre.css({'top': (opts.height - btn_pre.height()) / 2}); 221 btn_next.css({'top': (opts.height - btn_next.height()) / 2}); 222 223 btn_pre.click(function(){ 224 pre(); 225 }); 226 btn_next.click(function(){ 227 next(); 228 }); 229 } 230 231 232 // 作为上一个图片 233 function as_pre(img) 234 { 235 img.li.css({ 236 'width': img.pre.width, 237 'height': img.pre.height, 238 'left': img.pre.left, 239 'top': img.pre.top, 240 'opacity': 1 241 }); 242 } 243 244 // 作为当前图片 245 function as_cur(img) 246 { 247 img.li.css({ 248 'width': img.center.width, 249 'height': img.center.height, 250 'left': img.center.left, 251 'top': img.center.top, 252 'opacity': 1 253 }); 254 } 255 256 // 作为下一个图片 257 function as_next(img) 258 { 259 img.li.css({ 260 'width': img.next.width, 261 'height': img.next.height, 262 'left': img.next.left, 263 'top': img.next.top, 264 'opacity': 1 265 }); 266 } 267 268 // 下一个图片出现的初始化 269 function next_init(img) 270 { 271 img.li.css({ 272 'width': 0, 273 'height': 0, 274 'left': opts.width, 275 'top': opts.height / 2, 276 'opacity': 0 277 }); 278 } 279 280 // 上一个图片出现的初始化 281 function pre_init(img) 282 { 283 img.li.css({ 284 'width': 0, 285 'height': 0, 286 'left': 0, 287 'top': opts.height / 2, 288 'opacity': 0 289 }); 290 } 291 292 // 图片初始化 293 function img_init() 294 { 295 // 遍历图片,创建图片状态缓存 296 $('li', $this).each(function(){ 297 var _this = $(this); 298 var img = $('img', _this); 299 var alt = img.attr('alt') || ''; 300 var width = img.width(); 301 var height = img.height(); 302 303 _this.append('<div class="alt"><p>' + alt + '</p></div>'); 304 imgs.push({ 305 img: img, 306 li: _this, 307 div: $('div', _this), 308 center: { 309 width: width, 310 height: height, 311 left: (opts.width - width) / 2, 312 top: (opts.height - height) / 2 313 }, 314 pre: { 315 width: width / 2, 316 height: height / 2, 317 left: (opts.width - width) / 4, 318 top: opts.height / 2 - height / 4 319 }, 320 next: { 321 width: width / 2, 322 height: height / 2, 323 left: opts.width * 3 / 4- width / 4, 324 top: opts.height / 2 - height / 4 325 } 326 }); 327 img.width('100%').height('100%'); 328 }); 329 330 pre_img = imgs[0]; 331 cur_img = imgs[1]; 332 next_img = imgs[2]; 333 current = 1; 334 335 pre_img.li.addClass('pre_img'); 336 cur_img.li.addClass('cur_img'); 337 next_img.li.addClass('next_img'); 338 339 as_pre(pre_img); 340 as_cur(cur_img); 341 as_next(next_img); 342 343 pre_img.li.show(); 344 cur_img.li.show(); 345 next_img.li.show(); 346 alt_show(cur_img); 347 } 348 349 function wrap_init() 350 { 351 wrap.addClass('xsh_slider'); 352 wrap.css({ 353 'width': opts.width, 354 'height': opts.height 355 }); 356 } 357 358 // 自动播放 359 function auto_play() 360 { 361 if (opts.auto) 362 { 363 timeout = setInterval(function(){ 364 next(); 365 }, opts.delay); 366 } 367 } 368 369 // 初始化 370 function init() 371 { 372 wrap_init(); 373 btn_create(); 374 img_init(); 375 bind_click(); 376 auto_play(); 377 mousewheel(); 378 } 379 380 // 鼠标滚轮事件 381 function mousewheel() 382 { 383 wrap.mousewheel(function(event, delta, deltaX, deltaY){ 384 if (delta > 0) 385 next(); 386 else 387 pre(); 388 389 return false; 390 }); 391 } 392 }; 393 394 // 默认参数 395 $.fn.xsh_slider.defawrapts = { 396 pre_text: '<', 397 next_text: '>', 398 width: 960, 399 height: 400, 400 speed: 500, 401 delay: 5000, 402 auto: true 403 }; 404 405 // 阻尼动画切换效果 406 $.extend( 407 $.easing, { 408 easeOutExpo: function (x, t, b, c, d) { 409 return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; 410 } 411 } 412 ); 413 })(jQuery); 414 415 // 引用的鼠标滚轮 jquery 插件 416 /*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) 417 * Licensed under the MIT License (LICENSE.txt). 418 * 419 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. 420 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. 421 * Thanks to: Seamus Leahy for adding deltaX and deltaY 422 * 423 * Version: 3.0.6 424 * 425 * Requires: 1.2.2+ 426 */ 427 (function($){ 428 var types = ['DOMMouseScroll', 'mousewheel']; 429 430 if ($.event.fixHooks) { 431 for ( var i=types.length; i; ) { 432 $.event.fixHooks[ types[--i] ] = $.event.mouseHooks; 433 } 434 } 435 436 $.event.special.mousewheel = { 437 setup: function() { 438 if ( this.addEventListener ) { 439 for ( var i=types.length; i; ) { 440 this.addEventListener( types[--i], handler, false ); 441 } 442 } else { 443 this.onmousewheel = handler; 444 } 445 }, 446 447 teardown: function() { 448 if ( this.removeEventListener ) { 449 for ( var i=types.length; i; ) { 450 this.removeEventListener( types[--i], handler, false ); 451 } 452 } else { 453 this.onmousewheel = null; 454 } 455 } 456 }; 457 458 $.fn.extend({ 459 mousewheel: function(fn) { 460 return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); 461 }, 462 463 unmousewheel: function(fn) { 464 return this.unbind("mousewheel", fn); 465 } 466 }); 467 468 function handler(event) { 469 var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0; 470 event = $.event.fix(orgEvent); 471 event.type = "mousewheel"; 472 473 // Old school scrollwheel delta 474 if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; } 475 if ( orgEvent.detail ) { delta = -orgEvent.detail/3; } 476 477 // New school multidimensional scroll (touchpads) deltas 478 deltaY = delta; 479 480 // Gecko 481 if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { 482 deltaY = 0; 483 deltaX = -1*delta; 484 } 485 486 // Webkit 487 if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; } 488 if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; } 489 490 // Add event and delta to the front of the arguments 491 args.unshift(event, delta, deltaX, deltaY); 492 493 return ($.event.dispatch || $.event.handle).apply(this, args); 494 } 495 496 })(jQuery);
css
1 .xsh_slider { 2 padding: 0; 3 list-style: none; 4 overflow: hidden; 5 position: relative; 6 } 7 .xsh_slider li { 8 position: absolute; 9 overflow: hidden; 10 opacity: 0; 11 filter: alpha(opacity = 0); 12 } 13 .xsh_slider .alt { 14 position: absolute; 15 bottom: 0; 16 display: none; 17 } 18 .xsh_slider img { 19 border: none; 20 } 21 .xsh_slider .pre_img, .xsh_slider .next_img { 22 z-index: 1; 23 cursor: pointer; 24 } 25 .xsh_slider .cur_img { 26 z-index: 2; 27 } 28 .xsh_slider .btn_pre, .xsh_slider .btn_next { 29 position: absolute; 30 cursor: pointer; 31 } 32 .xsh_slider .btn_pre { 33 left: 0; 34 } 35 .xsh_slider .btn_next { 36 right: 0; 37 }
惭愧的说,代码写得不怎么样,纯粹面向过程写法。
最后附上下载:xsh_slide.7z