轮播效果在网页中用的很多,swiper是其中最有代表性的作品,它支持水平和竖直滑动,还有反弹效果,兼容移动端和pc端。当然代码量也是相当大的,单是js就有5300行(3.4.0的未缩版本),若不考虑代码利用率和加载速度直接就用了,在移动端比较慎重,比如京东(m.jd.com)的轮播就没有用它,而是自己实现了类似的功能,代码量很少的样子(格式化之后看起来二三百行左右的样子)。那么这个功能如果自己来实现,要怎么做呢?
准备工作
1. 准备几张图片(我这里放了四张)
2. 搭建目录结构(html+css+images+js)
3. 编写代码,实现初始状态的显示效果
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title>轮播</title>
<link rel="stylesheet" type="text/css" href="slider.css" rel="external nofollow" >
<script src="slider.js"></script>
</head>
<body>
<div id="slider" class="slider-wrapper">
<ul class="slider-items">
<li class="slider-item"><img src="images/pic21.gif" alt="1"></li>
<li class="slider-item"><img src="images/pic22.gif" alt="2"></li>
<li class="slider-item"><img src="images/pic23.gif" alt="3"></li>
<li class="slider-item"><img src="images/pic24.gif" alt="4"></li>
</ul>
</div>
<script>
Slider('#slider',{});
</script>
</body>
</html>
</div>
写几行样式,先让页面有一种滚动前的初始画面。
body {
padding: 0;
min-width: 300px;
max-width: 640px;
margin: 0 auto;
}
ul {
list-style: none;
}
ul,li {
margin: 0;
padding: 0;
}
.slider-wrapper {
position: relative;
width: 100%;
height: 220px;
overflow: hidden;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.slider-items {
position: relative;
height: 100%;
}
.slider-item {
float: left;
text-align: center;
cursor: pointer;
}
.slider-item > img {
width: 100%;
pointer-events: none;
}
.slider-pagination {
position: absolute;
bottom: 10px;
left: 0;
width: 100%;
text-align: center;
-webkit-transition-duration: .3s;
-moz-transition-duration: .3s;
-o-transition-duration: .3s;
transition-duration: .3s;
}
.slider-bullet {
width: 8px;
height: 8px;
margin: 0 5px;
display: inline-block;
border-radius: 100%;
background-color: black;
opacity: .2;
cursor: pointer;
}
.slider-bullet-active {
opacity: 1;
background-color: #007aff;
}
.slider-button {
position: absolute;
top: 50%;
width: 50px;
height: 50px;
text-align: center;
line-height: 50px;
margin-top: -25px;
z-index: 10;
font-size: 4rem;
color: gray;
-webkit-user-select:none;
user-select:none;
}
.next {
right: 0px;
}
.prev {
left: 0px;
}
</div>
做好这个静态页,可以帮助我们在开发过程中预览效果,方便查找问题,欣赏制作过程带来的乐趣。
在线预览
搭建程序骨架
接下来就是写js了,先搭一个程序的架子,我这里仿一下jQ的无new式设计(其实是自己在内部自动实现new的过程)
;( function( global, factory ) {
"use strict";
if ( typeof module === "object" && typeof module.exports === "object" ) {
module.exports = global.document ?
factory( global, true ) :
function( w ) {
if ( !w.document ) {
throw new Error( "Slider requires a window with a document" );
}
return factory( w );
};
} else {
factory( global );
}
// Pass this if window is not defined yet
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ){
"use strict";
function Slider( selector, options ) {
return new Slider.init( selector, options );
}
Slider.init=function(selector, params){
next:function(){},<br> prev:function(){},<br> move:function(){}
}<br> Slider.init.prototype = Slider.prototype = {<br> <br> };
return Slider
});
</div>
架子搭好之后,先停下来喝口水,思考一下,最终我们的这个插件要实现哪些功能。
1. 点击左、右箭头可以控制滚动
3. 可以向左、向右拖拽滑动
4. 返弹效果
5. 自动轮播效果
6. 页码指示
这些功能该怎么实现?
先画几张草图,在纸上模拟一下这个过程,搞明白之后,再用代码来让计算机执行。下图中的蓝框代表显示器的宽度,红框代表图片所在容器的实际宽度。我只要移动红框,那么在屏幕上看起来,就会有轮播滚动的效果。原理看起来是不是很简单?本着先易后难,循序渐进的作战方针,先不考虑循环滚动。假设屏幕上显示的是图片1,此时只要把红框往左移一个屏的宽度,那么就会显示2,再移一屏,就可以显示3. 向右滚动正好相反。

移动可以用css3的transform:translate3d来做,也可以用js变化left/top来做,用translate3d来做的核心代码如下:
function translate3d(element,x,y) {
x = x === undefined ? 0 : x;
y = y === undefined ? 0 : x;
element.style['-webkit-transform'] = 'translate3d(-'+x+'px,'+y+'px,0px)';
element.style['transform'] = 'translate3d(-'+x+'px,'+y+'px,0px)';
}
function transition(element,time){
element.style['-webkit-transition-duration'] = time+'ms';
element.style['transition-duration'] = time+'ms';
}
</div>
x控制左右移动,y控制竖直移动(本例中暂不考虑),z固定(0px). 当x移动的距离是正数的时候,向左滚动--prev,为负数的时候向右滚动--next
fn.next = function(){
var activeIndex = ++this.activeIndex;
translate3d(this.wrap,activeIndex*this.slideWidth);
transition(this.wrap,this.params.speed);
}
fn.prev = function(){
var activeIndex = --this.activeIndex;
translate3d(this.wrap,activeIndex*this.slideWidth);
transition(this.wrap,this.params.speed);
}
</div>
由于图片数量是有限的,不能一直滚动,如果到头了,需要做一些处理。因此需要判断activeIndex(当前显示的图片索引)的值。如果到了最右边就不能再允许滚动了。
var activeIndex = this.lastIndex--;<br>if(activeIndex > this.lastIndex){
return;
}
</div>
同理,到了最左边,也不能继续往左滚动了(听起来是一句非常正确的废话)
var activeIndex = --this.activeIndex;
if(activeIndex < this.firstIndex){
return;
}
</div>
现在要考虑自动滚动的情况,如果是自动轮播的情况,那就不能直接return; 要么当到达最右边的时候,activeIndex赋成firstIndex,当达到最左边的时候,activeIndex赋成lastIndex; 这样做的实际效果看起来就是像荡秋千一样,这显然不是我们想要的效果。要么跳到最前面重新开始,这做出来的实际效果一点也不连续。最后决定去看看swiper是怎么实现的。swiper的做法就是把第一张复制一份放到最后面,把最后一张复制一份插到最前面。 如下图所示:

第一张和第四张都被复制了一份。对应的代码如下:
fn.createLoopItems = function(){
var lastItem = this.slides[this.las

