js实现无缝轮播图插件(底部附源码)

我的博客已经全部迁移至新地址,欢迎收藏我的个人博客

推荐一个自己的博客:JS -- 手动实现数组原生方法

看了几个网上的轮播图例子,然后理解了其中的原理,自己写了一个插件,实现了无缝轮播。

先来说一下实现原理:

1. 首先要明确做一个插件的基本要求,我认为至少需要满足以下几点要求:具备默认设置参数的功能;插件自身的作用域与用户的作用域相互独立;用户可以自己调节参数达到自己想要的效果。

2. 然后看一下轮播图的需求。

我们需要实现下图所示的轮播图,它具有以下功能:

A.  每隔一定的时间图片自动播放;

B.   点击对应的圆点跳转到对应的图片;

C.  点击两边的按钮可以播放上一张图或者下一张图;

D.  当鼠标悬停在图片上方时暂停播放。

3. 然后需要考虑轮播图从何下手。

首先要实现功能A,这里已默认5张图为例,真实的图片肯定不是五张,这个想必大家都已知道,如果后台仍然使用5张图就不可能实现真正的无缝了。而在此我们不仅要实现自动播放,还要实现按钮功能,所以我们还需有第一张图跳转到最后一张图的功能,所以需要7张图片。然后要实现图片轮播的效果就要让图片在一条线上,使用float可以轻松实现(这里要注意,我们整个框架是:div>ul>li>img,div和li,img肯定是固定宽高,而ul就需要内容撑开宽度了,我们不知道图片的数量,如果固定了宽度,就会造成图片不再一条线上);接着要让他动起来,我们首先想到的是通过改变ul的left值来改变图片的显示,当然这里我也用的是left,但是如果使用left会降低效率,不如用translateX()更加高效。不过那个还没有做出来,等后面做出来了再修改一下。自动播放就是把这个功能放在一个setInterval()里面就可以了。

其次要实现功能B,看到这个功能我们想到的是如何将圆点与图片连接起来,还有处理圆点的点击事件。针对前一个问题,我的解决方法是给span(圆点)添加data-index属性,并对其编号,这样我们通过点击获得的编号就可以知道要跳转到哪张图片了。针对后一个问题,我想到了可以给span外面包一层div,然后给div添加点击事件,通过事件冒泡得到事件源(即target属性),然后获取事件源的data-index即可。

然后是功能C,这个就比较简单了,右边的按钮就是触发一次播放的动画,左边的按钮就是反方向触发一次放的动画。

最后是功能D,可以通过hover()清除setInterval(),移除后重新创建一个。

考虑到插件的兼容性,即因为图片数量是未知的,所以小圆点span标签需要动态创建,同时对两个按钮也动态创建。

4. 了解了所有需求以及实现方法就要开始正式写代码了。

先附上结构

<div class="wrapper">
		<div class="box">
			<ul class="carousel-inner">
				<li class="carousel-item"><img src="./images/1.jpg" alt=""></li>
				<li class="carousel-item"><img src="./images/2.jpg" alt=""></li>
				<li class="carousel-item"><img src="./images/3.jpg" alt=""></li>
				<li class="carousel-item"><img src="./images/4.jpg" alt=""></li>
				<li class="carousel-item"><img src="./images/5.jpg" alt=""></li>
				<li class="carousel-item"><img src="./images/6.jpg" alt=""></li>
				<li class="carousel-item"><img src="./images/7.jpg" alt=""></li>
			</ul>
		</div>
	</div>

 

首先我们扩展一个封装函数sowingMap(),并在函数内通过jq的extend方法处理参数,如果用户没有传进来参数就使用默认参数。

 

(function() {
    $.fn.sowingMap = function(option) {
        var args = $.extend({
            count : 2,//图片数量
            time : 3000 //自动播放时间间隔
        }, option);
    }
})(jQuery);

 

为了结构看起来清楚明了,我另外创建了一个“构造函数”Init(),并在此函数的原型链上编程。

 

function Init(ele, args) { //ele:父级节点,args:参数列表
        if (args.count > 1) {
            this.init(ele, args);
        } else {
            alert('请输入正确的图片数量')
        }
    }
    Init.prototype = {}

 

在原型链上,首先写一个入口函数init()处理传进来的参数,并初始化后面需要用到的dom节点,调用主要函数。

 

init : function(ele, args) {
            this.ele = ele,
            this.count = args.count,
            this.time = args.time,
            this.index = 0,
            this.oUl = this.ele.find('.carousel-inner'),
            this.oLi = this.oUl.find('.carousel-item'),
            this.createSpan(), //生成圆点以及左右按钮
            this.handleUl(), //处理图片
            this.automatic(), //自动播放
            this.eventBind()  //点击事件
        }

 

然后写一个handleUl()方法,用来处理图片,即复制最后一张图片并将其接在第一位,复制第一张图片并将其接在最后一位。

 

handleUl : function() {
            var last = this.oLi.eq(0).clone(),
                first = this.oLi.eq(this.count - 1).clone(),
                width = this.ele.width(),
                left = - (this.index + 1) * this.ele.width(); //确认第一张图片的位置
            this.oUl.prepend(first).append(last).css('left', left + 'px');
            this.oUl.width((this.count + 2 ) * width);
        }

 

接着写一个createSpan()方法,用来动态创建span标签以及btn按钮。

 

createSpan : function() {
            var str = '<div class="carousel-indicators">';
            for (var i = 0; i < this.count; i ++) {
                str += '<span data-index="' + i + '"></span>';
            }
            str += '</div><span class="carousel-btn carousel-prev-btn"></span>' 
            + '<span class="carousel-btn carousel-next-btn"></span>';
            this.ele.append(str);
            this.ele.find('.carousel-indicators span').eq(this.index).addClass('active')
        }

 

接着就是处理动画了,首先写一个ianimate()方法,用来处理动画,在这里面要注意,当图片动画结束后我们要处理圆点的效果以及图片的衔接问题。

 

ianimate : function(ileft) {
            var tleft = this.oUl.position().left,
            i = this;
                i.oUl.animate({
                    left : ileft + tleft
                }, function() {
                    var left = i.oUl.position().left,
                        width = i.ele.width();
                    ileft > 0 && left > -width && i.oUl.css('left', - i.count * width); //判断是否是第0张(即最前面的最后一张)
                    ileft < 0 && left <  - i.count * width && i.oUl.css('left', -width); //判断是否是最后一张(即最后面的第一张)
                    i.index = parseInt(- left / width) - 1;
                    i.index = i.index > i.count - 1 ? 0 : i.index;
                    i.index = i.index < 0 ? i.count - 1 : i.index;
                    i.renBtns(); // 给圆点添加特效
            })
        }

 

接着是renBtns()方法,通过给对应的span添加类名来改变样式。

 

renBtns : function() {
            this.ele.find('.carousel-indicators span').removeClass("active").eq(this.index).addClass('active')
        }

 

当动画做好后就要去触发动画了,写一个eventBind()方法来放置圆点以及按钮的点击事件还有外层div的hover事件。

 

eventBind : function() {
            var i = this,
                prev = this.ele.find(".carousel-prev-btn"),
                next = this.ele.find(".carousel-next-btn"),
                span = this.ele.find(".carousel-indicators"),
                ileft = this.ele.width();
            prev.on('click', function(event) {
                i.ianimate(ileft);
            });
            next.on('click', function(event) {
                i.ianimate(-ileft);
            });
            span.on('click', function(event) {
                var e = event || window.event;
                var target = e.target || e.srcElement;
                i.ianimate(- ($(target).data('index') - i.index) * ileft);
            });
            i.ele.hover(function() {
                clearInterval(i.timer);
            }, function() {
                i.automatic();
            })
        }

 

要处理外层div的hover事件,自然先要写一个方法automatic()用来触发动画自动播放。

 

automatic : function() {
            var next = this.ele.find(".carousel-next-btn");
            this.timer = setInterval(function() {
                next.trigger('click')
            }, this.time)
            
        }

 

为了保证动画的流畅程度,在动画开始之前需要加一个判断,判断现在是否有正在进行的动画,刚开始我想到了加锁,但发现不是很好操作,于是查了一下文档,发现可以通过jq内置的is()方法来判断当前是否有动画在进行,如下。

 

if(!i.oUl.is(":animated")) {
       //动画
}

 

最后我们只需要引用此插件并调用就可以了

 

$('.box').sowingMap({
			count : 7,
			time : 3000
		});

 

至此,主要功能以及编写完毕,只需要在处理一下细节,一个轮播图插件就做好了。

 

附上源码下载链接:js实现无缝轮播图插件,欢迎加QQ:1759668379一起学习。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值