前言:最近在做一个音乐播放器,首页要做一个图片轮播,看了bootstrap的carousel插件以及移动端的swipe.js库,都是平面图片轮播的效果,所以自己想着实现类似网易云app里那种3d图片轮播的效果,所以写下此文.
源代码:here
demo演示: here
使用方法:
首先,引入Swipe.js和Swipe.css
html结构如下:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>图片轮播3d效果</title> 8 <link rel="stylesheet" href="swipe.css"> 9 </head> 10 <body> 11 <div class="slide_box"> 12 <ul class="slide_list swipe" id="swipe_list" data-ride='swipe'> 13 <li class="item"> 14 <a href="" class="slide_list_link"> 15 <img src="https://y.gtimg.cn/music/common/upload/t_focus_info_iphone/67011.jpg" alt="" class="slide_list_pic"> 16 </a> 17 </li> 18 </ul> 19 <div class="slide_action"> 20 <a href="##" class="slide_action_btn-left"><span class=" glyphicon glyphicon-home" ></span></a> 21 <a href="##" class='slide_action_btn-right'><span class=" glyphicon glyphicon-home" ></span></a> 22 </div> 23 </div> 24 <script src="http://cdn.bootcss.com/jquery/3.0.0-rc1/jquery.js"></script> 25 <script src='swipe.js'></script> 26 </body> 27 </html>
然后脚本中加上以下代码,即可实现
1 $(window) 2 .on('load', function () { 3 var swipes = $('[data-ride="swipe"]') 4 swipes.each(function (index, item) { 5 var swipe = new Swipe(item) 6 swipe.init() 7 }); 8 })
实现原理
- 定义了一个Swipe构造函数,主要通过对每一个item添加删除类,结合css的transform属性的translate3d()来实现滚动3d效果,这里只是实现一个简单的效果,具体的可以继续扩展
- CSS中主要有五个类来实现动画效果p0,p1,p2,p3,p4;
类p2是主要呈现的图片,初始化的时候会默认最中间的图片添加p2类,然后左边的图是p0,p1类,右边的是p3,p4类;
p0,p4主要是隐藏在后边的图片,设计这两个类是为了动画更加的流畅。
大概这么说吧,比如我们有7张图片,那么默认会初始化this.$itemIndenxArr=[0,0,1,2,3,4,4];
然后根据 this.$itemIndenxArr 分别添加类 p0,p0,p1,p2,p3,p4,p4,就可以实现初始效果图如下:
- 在Swipe.prototype.prev以及Swipe.prototype.next中通过对this.$itemIndexArr的修改,来实现图片的滚动效果
当向左滚动,会修改 this.$itemIndenxArr=[4,0,0,1,2,3,4];此时呈现在中间的就是第五张图
Swipe.prototype.slide判断滚动方向进行实际的滚动(即实际的添加删除类)
总结:
总得来说,实现原理不难,基本上实现了图片的响应式,以及任意图片添加都可以实现此轮播效果,对于以后实现都可以直接引入代码,感觉还是不错的
更全面的内容请看 这一篇 《3D轮播插件》
具体代码如下:
index.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>图片轮播3d效果</title> 8 <link rel="stylesheet" href="swipe.css"> 9 </head> 10 <body> 11 <div class="slide_box"> 12 <ul class="slide_list swipe" id="swipe_list" data-ride='swipe'> 13 <li class="item"> 14 <a href="" class="slide_list_link"> 15 <img src="https://y.gtimg.cn/music/common/upload/t_focus_info_iphone/67011.jpg" alt="" class="slide_list_pic"> 16 </a> 17 </li> 18 </ul> 19 <div class="slide_action"> 20 <a href="##" class="slide_action_btn-left"><span class=" glyphicon glyphicon-home" ></span></a> 21 <a href="##" class='slide_action_btn-right'><span class=" glyphicon glyphicon-home" ></span></a> 22 </div> 23 </div> 24 <script src="http://cdn.bootcss.com/jquery/3.0.0-rc1/jquery.js"></script> 25 <script src='swipe.js'></script> 26 </body> 27 </html>
Swipe.js
1 var Swipe = function (element) { 2 this.$element = $(element) 3 this.$item = $(element) 4 .children('.item') 5 this.$length = $(element) 6 .children('.item') 7 .length 8 this.$itemIndexArr = [] 9 for (var i = 0, len = this.$length; i < len; i++) { 10 if (i < Math.floor(len / 2)) 11 this.$itemIndexArr[i] = 0 12 else if (i > Math.floor(len / 2)) 13 this.$itemIndexArr[i] = 4 14 if (i == Math.floor(len / 2) - 1) 15 this.$itemIndexArr[i] = 1 16 if (i == Math.floor(len / 2)) 17 this.$itemIndexArr[i] = 2 18 if (i == Math.floor(len / 2) + 1) 19 this.$itemIndexArr[i] = 3 20 } 21 } 22 Swipe.prototype.DEFAULTS = { 23 interval: 3000, 24 pause: 'hover' 25 } 26 Swipe.prototype.init = function () { 27 28 var that = this 29 that.$item.each(function (index, item) { 30 $(item) 31 .addClass('p' + that.$itemIndexArr[index]) 32 }) 33 that.cycle() 34 var links = this.$element.siblings('.slide_action') 35 .find('a') 36 links.each(function (index, item) { 37 var type = $(item) 38 .attr('class') 39 .match(/left/) ? 'prev' : 'next' 40 switch (type) { 41 case 'prev': 42 $(this) 43 .bind('click', function () { 44 that.prev() 45 }) 46 break; 47 case 'next': 48 $(this) 49 .bind('click', function () { 50 that.next() 51 }) 52 break; 53 } 54 }); 55 } 56 Swipe.prototype.cycle = function () { 57 var that = this 58 var cycleInterval = setInterval(function () { 59 return that.next() 60 }, that.DEFAULTS.interval) 61 } 62 Swipe.prototype.next = function () { 63 var len = this.$length 64 var indexArr = this.$itemIndexArr 65 this.$itemIndexArr = indexArr.map(function (item, index) { 66 if (item === 4 && indexArr[(index + 1) % len] === 0) { 67 return 0; 68 } else if (item === 4) { 69 return 4; 70 } 71 return item + 1; 72 }) 73 return this.slide(); 74 } 75 Swipe.prototype.prev = function () { 76 var len = this.$length 77 var indexArr = this.$itemIndexArr 78 this.$itemIndexArr = indexArr.map(function (item, index) { 79 if (item === 0 && indexArr[(index + len - 1) % len] === 4) { 80 return 4; 81 } else if (item === 0) { 82 return 0; 83 } 84 return item - 1; 85 }) 86 return this.slide(); 87 } 88 Swipe.prototype.slide = function () { 89 var indexArr = this.$itemIndexArr 90 this.$item.removeClass('p0 p1 p2 p3 p4') 91 this.$item.each(function (index, item) { 92 $(item) 93 .addClass('p' + indexArr[index]) 94 }) 95 }
Swipe.css
1 @media (min-width : 996px){ 2 html { 3 font-size: 102.4px; 4 } 5 } 6 @media (min-width : 667px) and (max-width :996px){ 7 html { 8 font-size: 66.7px; 9 } 10 } 11 @media (min-width : 375px) and (max-width : 667px){ 12 html { 13 font-size: 37.5px; 14 } 15 } 16 /* ============================================================= 17 Swiper styles 18 ========================================================================== */ 19 .slide_box { 20 position: relative; 21 overflow: hidden; 22 width: 10rem; 23 margin-bottom: 25px; 24 height: 4.5rem; 25 } 26 .slide_list { 27 position: relative; 28 width: 9rem; 29 max-height: 361px; 30 } 31 .slide_list>.item { 32 position: absolute; 33 display: inline-block; 34 top: 0; 35 /* left: 0; */ 36 width: 7rem; 37 left: calc(50% - 3rem); 38 height: 4.5rem; 39 max-height: 325px; 40 /* margin: 0 auto; */ 41 /*opacity: 0;*/ 42 filter: alpha(opacity=0); 43 z-index: 1; 44 -webkit-transition: all 300ms ease-in-out; 45 -ms-transition: all 300ms ease-out; 46 transition: all 300ms ease-out; 47 } 48 .slide_list>.item.p2 { 49 z-index: 10; 50 } 51 .slide_list>.item.p1 { 52 /*向左移动 并且放小*/ 53 -webkit-transform: translate3d(-116px,0,0) scale(0.81); 54 transform: translate3d(-116px,0,0) scale(0.81); 55 } 56 .slide_list>.item.p1,.slide_list>.item.p3{ 57 opacity: .8; 58 filter: none; 59 } 60 .slide_list>.item.p0,.slide_list>.item.p4{ 61 opacity: 0; 62 filter: none; 63 } 64 /*向左滚动*/ 65 .slide_list>.item.p1{ 66 transform-origin: 0 50%; 67 } 68 /*向右滚动*/ 69 .slide_list>.item.p3 { 70 transform-origin: 100% 50%; 71 } 72 .slide_list>.item.p0 { 73 -webkit-transform: translate3d(-328pxpx,0,0) scale(0.41); 74 transform: translate3d(-328px,0,0) scale(0.41); 75 } 76 .slide_list>.item.p3 { 77 -webkit-transform: translate3d(116px,0,0) scale(0.81); 78 transform: translate3d(116px,0,0) scale(0.81); 79 } 80 .slide_list>.item.p4 { 81 -webkit-transform: translate3d(328px,0,0) scale(0.41); 82 transform: translate3d(328px,0,0) scale(0.41); 83 } 84 @media screen and (min-960px) { 85 .slide_list>.item { 86 left: calc(50% - 3.5rem); 87 } 88 } 89 .event_list_pic { 90 width: 100%; 91 height: 100%; 92 } 93 .slide_list_link { 94 /* 10%; */ 95 height: 100%; 96 } 97 .slide_list_pic { 98 width: 100%; 99 } 100 .slide_action { 101 position: absolute; 102 top: 0; 103 width: 100%; 104 height: 100%; 105 overflow: hidden; 106 } 107 [class^=slide_action_btn] { 108 position: absolute; 109 top: 50%; 110 margin-top: -54px; 111 width: 72px; 112 height: 108px; 113 background: rgba(153,153,153,.4); 114 opacity: 0; 115 visibility: none; 116 transition-property: opacity,transform; 117 transition-duration: .5s; 118 z-index: 2; 119 } 120 [class^=slide_action_btn]:hover { 121 opacity: 1.0; 122 } 123 .slide_action-left,.slide_action_btn-left { 124 left: 0; 125 } 126 .slide_sction-right,.slide_action_btn-right { 127 right: 0; 128 }