1.需求:
目前项目中很多页面都用到了轮播图,虽然轮播图的展现形式不一样,但是我们可以把轮播图的共性给抽象出来,开发出一款插件,让使用到轮播图的页面都引用这个插件.当前这款插件是使用jquery开发的,兼容IE8.
2.结果图:
2.具体实现
2.1 js文件
(function(){
function Carousel(options){
this.dom = (options.dom instanceof $)?options.dom:$(options.dom);
this.hasDots = options.hasDots || false;//轮播图是否包含指示器
this.duration = options.duration || 5000;//自动轮播的时间
this.autoScroll = options.autoScroll || false; //是否开启自动轮播呢
this.index = 0;//当前的索引
this.hasLeftAndRight = options.hasLeftAndRight || false; //是否有左右点击框
this.scrollSpeed = options.scrollSpeed || 250;//轮播滑动切换的时间
this.leftAndRightCallback = options.leftAndRightCallback || function(){};//当含有左右点击按钮时的回调函数
if(window.getComputedStyle){//计算轮播图每一项的宽度,下面的写法是兼容ie8
this.item_width = parseInt(getComputedStyle(this.dom.find(".item-hook")[0]).width);
}else{
this.item_width = parseInt(this.dom.find(".item-hook")[0].currentStyle.width);
}
this.count = this.dom.find(".item-hook").length;//计算轮播图的数量
this.init();
}
/**
* 初始化
*/
Carousel.prototype.init = function(){
if(this.autoScroll){ //轮播图是否自动轮播
this.setLoop();
this.bindEvent();
}
this.setDots();
this.updateLeftAndRight(0);
this.bindLeftAndRightEvent();
}
/**
* 左右事件的绑定
*/
Carousel.prototype.bindLeftAndRightEvent = function(){
var _this = this;
this.dom.find(".left-hook").on("click",function(){
_this.updateView(_this.index-1);
_this.updateLeftAndRight(_this.index-1);
})
this.dom.find(".right-hook").on("click",function(){
_this.updateView(_this.index+1);
_this.updateLeftAndRight(_this.index+1);
})
}
/**
* 更新左右框的状态
*/
Carousel.prototype.updateLeftAndRight = function(index){
if(!this.hasLeftAndRight){
return false;
}
this.index = index;
if(this.index == 0){
this.dom.find(".left-hook").hide();
this.dom.find(".right-hook").show();
}else if(this.index == this.count-1){
this.dom.find(".left-hook").show();
this.dom.find(".right-hook").hide();
}else{
this.dom.find(".left-hook").show();
this.dom.find(".right-hook").show();
}
this.leftAndRightCallback(this.index);
}
/**
* 设置轮播图的小点点
*
* 根据轮播图上面的有几个元素就生成几个指示器,并且给指示器绑定点击事件
*
*/
Carousel.prototype.setDots = function(){
if(!this.hasDots){
return false;
}
var list = this.dom.find(".dots-hook");
var itemHtml =$("<div></div>").append($(list.find(".dots-item-hook").removeClass("current").get(0)).clone()).html();
var length = this.dom.find(".item-hook").length;
if(length<=1){
list.hide();
return false;
}
var dots_content="";
for(var i = 0;i<length;i++){
dots_content+=itemHtml;
}
list.html(dots_content);
$(list.find(".dots-item-hook").get(0)).addClass("current");
var _this =this;
list.on("click",function(e){
var target = e.target || window.srcElement;
if(!$(target).hasClass("dots-item-hook")){
return false;
}
var index = $(target).index();
_this.updateView(index);
})
}
/**
* 渲染轮播图
*
* 通过获取到的索引值触发轮播图滚动到指定索引的位置
*
*
*/
Carousel.prototype.updateView = function(index){
if(this.index == index){
return false;
}
var list = this.dom.find(".list-hook");
var symbol = this.index -index;
var _this = this;
if(symbol>0){ //点击小圆点向右滚
var arr = Array.prototype.slice.call(list.find(".item-hook"),0);
var dom_item = arr.splice(arr.length-this.index,this.index);
arr = dom_item.concat(arr);
list.append(arr);
list.css("left",-1*this.index*this.item_width);
list.animate({
left:-1*index*this.item_width
},this.scrollSpeed,function(){
_this.afterScrollHandler(index,index);
})
}else{ //向左滚
list.animate({
left:symbol*this.item_width
},this.scrollSpeed,function(){
_this.afterScrollHandler(index,Math.abs(symbol));
})
}
}
/**
* 轮播图滚动后后处理
*/
Carousel.prototype.afterScrollHandler = function(index,num){
var list = this.dom.find(".list-hook");
this.index = index;
var arr = Array.prototype.slice.call(list.find(".item-hook"),0);
var del_datas = arr.splice(0,num);
arr = arr.concat(del_datas);
list.append(arr);
list.css("left",0);
this.updateDots();
}
/**
* 渲染小红点
*/
Carousel.prototype.updateDots = function(){
var list = this.dom.find(".dots-hook");
list.find(".dots-item-hook").removeClass("current");
$(list.find(".dots-item-hook")[this.index]).addClass("current");
}
/**
* 设置定时器循环播放
*
* 每过5s就改变一次外部容器div的left的值,让其产生向左滑动的效果,滑动完毕
* 后将轮播图的第一个元素提出来塞到队伍的最后一个,并将外部容器left的值恢复为0
*/
Carousel.prototype.setLoop = function(){
var _this = this;
this.timer = setInterval(function(){
var list = _this.dom.find(".list-hook");
list.animate({
left:-1*_this.item_width+"px"
},250,function(){
_this.index++;
if(_this.index>=_this.count){
_this.index = 0;
}
_this.updateDots();
$(list.find(".item-hook")[0]).appendTo(list);
list.css("left",0);
})
},_this.duration)
}
/**
* 绑定鼠标触摸事件
*
* 定义鼠标划入和划出的两个事件,滑入时让轮播图暂停自动轮播,划出时恢复自动轮播
*
*/
Carousel.prototype.bindEvent = function(){
var list = this.dom.find(".list-hook");
var _this = this;
this.dom.on("mouseenter",function(){
clearInterval(_this.timer);
_this.timer = null;
})
this.dom.on("mouseleave",function(){
_this.timer = setInterval(function(){
list.animate({
left:-1*_this.item_width+"px"
},250,function(){
_this.index++;
if(_this.index>=_this.count){
_this.index = 0;
}
_this.updateDots();
$(list.find(".item-hook")[0]).appendTo(list);
list.css("left",0);
})
},_this.duration)
})
}
window.Carousel = Carousel;
}
)();
2.2 html形式
<!--banner轮播图-->
<div class="banner-carousel" id="carousel">
<div class="list list-hook">
<div class="item item-hook"><img src="../img/static/banner1.png" /></div>
<div class="item item-hook"><img src="../img/static/banner2.png" /></div>
<div class="item item-hook"><img src="../img/static/banner3.png" /></div>
</div>
<ul class="dots-hook">
<li class="dots-item-hook current"></li>
<li class="dots-item-hook"></li>
<li class="dots-item-hook"></li>
</ul>
</div>
说明:html的内容可以多样化,但有几个类名必须要加上.轮播图列表包裹容器需要添加一个类名list-hook,每个轮播的对象要添加类名item-hook.如果需要使用到指示器,指示器的包裹容器需要添加上类名dots-hook,里面的单项需要添加上类名dots-item-hook.如果使用到了左右标识点击滑动,那么html上面相应的地方要加上类名,左标识加left-hook,右标识为right-hook.
2.3 css形式
具体的样式可以自由发挥,但有几点必须注意:
1.list-hook的父元素要设置position:relative和overflow:hidden
2.list-hook必须和父元素完全重合(宽高设置为100%即可),定位方式改为绝对定位,而且不能让子元素换行.这个地方注意一下,
list-hook的宽度并不等于几个item-hook的宽度和,而是list-hook的宽度=list-hook父元素宽度=每个item-hook的宽度 .
3.子元素设置为行内块元素,横向拍成一列
.banner-carousel {
width: 100%;
height: 452px;
position: relative;
overflow: hidden;
}
.list-hook{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
white-space: nowrap;
font-size: 0;
}
.item-hook{
width: 100%;
height: 100%;
display: inline-block;
}
3.具体使用
把页面的上的dom对象传进去,其次可以根据需求传递相应的参数
//初始化banner轮播图
new Carousel({
dom:$("#carousel"),
hasDots:true, //使用指示器
autoScroll:true //开启自动轮播
});
分析:
此轮播图最复杂的一块是js文件中的updateView方法.具体实现细节如下:
首先将当前的索引值和需要滚动的索引值相减得到symbol值,根据symbol值的正负可以轻易的知道当前轮播图需要向左滚动还是向右滚动.
如果是向左滚动很好处理,向左滑动若干个宽度,将滑动到左侧的几个元素提出来塞到队伍的后面去
向右滑动就有些麻烦了,首先要想办法把轮播图恢复到最初的那个顺序才能向左滑动.比如原来的轮播图顺序是1234,经过3轮自动轮播变成了4123.我现在点击1的指示器,想让第四个轮播图向左滑动到第一个,那该如何处理呢?先要想办法将4123恢复到1234才能向左滑动,只需要将4后面的123截下来提到4的前面去.arr.length-this.index就是需要截取的起始位置,截取下来后塞到队伍的前面去,就能恢复到最初的位置.在这里我们没有一个一个去改变dom元素的位置,而是先把dom元素的类数组对象转化成普通数组,在普通数组中调整好顺序,父元素再append该普通数组,就能立刻将页面上dom元素的顺序进行调整.