利用jquery实现轮播图-e6写法
2019-01-02 本文已影响1人
家里有棵核桃树
用了好久bootstrap提供的轮播图插件,刚好最近很闲,就自己实现轮播图效果练练手。bootstrap较早的版本都是利用原型的办法(有些也用了es6的proxy)实现的,最新的版本用的是es6的类(class)和一些模块的思想来实现。本文实现轮播效果的方法和bootstrap的实现不一样,但是会借鉴相关的代码风格。由于是练手demo在轮播插件的封装上考虑的不是太多。
1、使用
1.1 静态资源
使用js前要提前引用jquery,可以把该js文件放在</body>前引用。
1.2 HTML模板
把内容按如下格式装填好后,就可以出现轮播效果了(跟bootstrap类似)。轮播项的格式要和指示器的个数一一对应,轮播项和指示器缺一不可。
<!--carousel 轮播容器-->
<div class="carousel">
<!--carousel-inner 每一个轮播项内容-->
<div class="carousel-inner">
<div class="carousel-item active" data-index="0">
<a href="#">
<img class="carousel-img" src="img/1.png" alt="">
</a>
<div class="carousel-caption">
<h3>HEADER 1~</h3>
</div>
</div>
...
</div>
<!--carousel-indicators 指示器,指示当前显示的是第几项 也可以点击切换当前的显示项-->
<ul class="carousel-indicators">
<li class="active" data-index="0">1</li>
<li data-index="1">2</li>
<li data-index="2">3</li>
<li data-index="3">4</li>
<li data-index="4">5</li>
</ul>
<!--carousel-ctrl* 左右箭头,可上下切换当前的显示项【可省略】-->
<span class="carousel-ctrlPrev"><</span>
<span class="carousel-ctrlNext">></span>
</div>
1.3 效果
轮播呈现功能:
- 动态循环轮播
- 上下切换
- 点击跳转指定项
2、实现
2.1 轮播设计思想
(1)下一张的操作
让当前项的下一张显示出来,然后通过jquery提供的animate方法将盒子左移一个盒子的宽度(left: -盒子宽度;
),移动效果完成后,将最开始显示的那一项隐藏且设置当前盒子的左移大小为0(left: 0;
)。
如果当前项没有下一张,那么就把第一张插入到当前项的后面。再继续上面的操作。
(2)上一张的操作
让当前项的上一张显示出来,设置盒子的左移大小为一个盒子的宽度(left: -盒子宽度;
),然后通过jquery提供的animate方法将盒子的左移大小设置为0(left: 0;
),移动效果完成后,将最开始显示的那一项隐藏。
如果当前项没有上一张,那么就把最后一张插入到当前项的前面。再继续上面的操作。
(3)指示器指定显示项
先拿到显示项的序号,再判断滚动方向(next还是prev),通过滚动方向来确定下一项是插入到当前项的后面还是前面,继续上一张或下一张的操作。
2.2 代码
(1)js
// 用到的轮播图的相关模块
const Selector = {
BOX: '.carousel',
INNER: '.carousel-inner',
ACTIVE: '.active',
ACTIVE_ITEM: '.active.carousel-item',
ITEM: '.carousel-item',
NEXT: '.carousel-ctrlNext',
PREV: '.carousel-ctrlPrev',
INDICATORS: '.carousel-indicators',
};
// 轮播框大小
const Box = {
WIDTH: $(Selector.BOX).width(),
HEIGHT: $(Selector.BOX).height()
};
// 相关类名
const ClassName = {
ACTIVE : 'active'
};
// 方向
const Direction = {
NEXT: 'next',
PREV: 'prev'
};
// 默认配置
const Default = {
interval: 3000,
gap: 600
};
class Carousel {
constructor(selector, config) {
this._isPaused = false;
this._interval = null;
this._enableClickAction = true;
this._activeElement = $(Selector.ACTIVE_ITEM);
this._targetElement = null;
this._element = $(selector);
this._inner = $(Selector.INNER);
this._indicatorsElement = $(Selector.INDICATORS);
this._init();
}
pause() {
this._isPaused = true;
clearInterval(this._interval);
}
cycle() {
this._isPaused = false;
if (this._interval) {
// 重新开始轮播时 要重新更新定时器 不然显示有误差,因为有多个定时器存在
clearInterval(this._interval);
this._interval = null;
}
this._interval = setInterval(() => this._slide('next'), Default.interval);
}
_init() {
this._addEventListeners();
this.cycle();
}
_addEventListeners() {
// 下一页
$(Selector.NEXT).on('click', () => this._slide('next'));
// 上一页
$(Selector.PREV).on('click', () => this._slide('prev'));
// 鼠标移入轮播暂停
$(Selector.BOX).on('mouseenter', () => this.pause());
// 鼠标移除轮播继续
$(Selector.BOX).on('mouseleave', () => this.cycle());
// 轮播框框被点击切换时 阻止过快点击出现的问题
$(Selector.BOX).on('click', () => {
if (this._enableClickAction) {
this._enableClickAction = false;
setTimeout(() => this._enableClickAction = true, Default.gap);
}
});
// 指示器点击时 切换到对应的图片
$(Selector.INDICATORS).on('click', 'li', event => this._slide('', $(event.target)));
}
_getActiveItemIndex() {
return this._activeElement.data('index');
}
_getTargetItemIndex($indicator = null, direction = 'next') {
if ($indicator) {
return $indicator.data('index');
} else {
let itemsLength = $(Selector.ITEM).length;
let index = Direction.NEXT == direction ? this._getActiveItemIndex() + 1 : this._getActiveItemIndex() - 1;
itemsLength == index && (index = 0);
-1 == index && (index = itemsLength - 1);
return index;
}
}
_isActiveItemOnEdge(direction) {
let $items = this._inner.find(Selector.ITEM);
return Direction.NEXT == direction
? this._activeElement[0] == $items.last()[0]
: this._activeElement[0] == $items.first()[0];
}
_setActiveIndicatorElement() {
this._indicatorsElement
.find(Selector.ACTIVE).removeClass(ClassName.ACTIVE)
.end()
.find(`[data-index='${this._getActiveItemIndex()}']`).addClass(ClassName.ACTIVE);
}
// $indicator 只有通过指示器改变轮播图才会用到
_slide(direction = 'next', $indicator = null) {
// 如果在短时间内多次点击 不进行任何操作
if(!this._enableClickAction) return false;
// 当轮播图开始滚动时 得到当前项和需要滚动到的指定目标项
this._activeElement = $(Selector.ACTIVE_ITEM);
this._targetElement = this._inner.find(`${Selector.ITEM}[data-index='${this._getTargetItemIndex($indicator, direction)}']`);
// 根据方向 将targetElement插入到对应的位置
$indicator && (direction = this._getTargetItemIndex($indicator) > this._getActiveItemIndex() ? 'next' : 'prev');
// 需要将目标项显示出来
this._targetElement.addClass('active');
// 根据不同的prev、next操作 判断是否需要改变列表排列顺序
let isActiveItemOnEdge = this._isActiveItemOnEdge(direction);
if (Direction.NEXT == direction && (isActiveItemOnEdge || $indicator)) {
// 将第一项放到最后一项
this._targetElement.appendTo(this._inner);
}
if (Direction.PREV == direction) {
// 将最后一项放到第一项,原始的盒子inner的left需要修改
(isActiveItemOnEdge || $indicator) && this._targetElement.prependTo(this._inner);
this._inner.css('left', -Box.WIDTH);
}
// 切换轮播图的显示
this._inner.animate({
left: Direction.NEXT == direction ? -Box.WIDTH : 0
}, Default.gap, 'linear',() => {
// 轮播图切换成功后的操作
this._activeElement.removeClass('active');
this._activeElement = this._targetElement;
this._inner.css('left', 0);
// 修改对应的指示器
this._setActiveIndicatorElement();
});
}
static _jQueryInterface(config) {
return new Carousel(this, config);
}
}
// new Carousel(Selector.BOX);
$.fn.carousel = Carousel._jQueryInterface;
$.fn.carousel.Constructor = Carousel;
$('.carousel').carousel();
(2)less
* {
margin: 0;
padding: 0;
}
@carouselWidth: 500px;
@carouselHeight: 300px;
.container {
box-sizing: content-box;
width: @carouselWidth;
height: @carouselHeight;
padding: 10px;
margin: 100px auto;
border: 1px solid #ccc;
}
.carousel {
position: relative;
width: @carouselWidth;
height: @carouselHeight;
overflow: hidden;
color: #666;
}
.carousel-inner{
position: absolute;
width: 200%;
height: 100%;
}
.carousel-item {
display: none;
width: @carouselWidth;
height: @carouselHeight;
float: left;
&.active {
display: block;
}
}
.carousel-caption {
position: absolute;
bottom: 0;
width: 100%;
height: 50px;
padding: 0 10px;
background: rgba(0, 0, 0, 0.2);
line-height: 50px;
}
.carousel-img {
width: 100%;
height: 100%;
}
.carousel-indicators {
position: absolute;
right: 10px;
bottom: 10px;
text-align: center;
li {
display: inline-block;
height: 20px;
width: 20px;
margin: 3px;
border-radius: 10px;
background-color: rgba(0, 0, 0, 0.3);
font-size: 13px;
line-height: 20px;
cursor: pointer;
&.active {
background-color: rgba(0, 0, 0, 0.6);
color: #bbb;
}
}
}
[class*='carousel-ctrl'] {
position: absolute;
top: 50%;
width: 40px;
height: 40px;
border: 1px solid #fff;
background: #fff;
color: #000;
opacity: 0.1;
font-family: '黑体';
font-weight: bold;
font-size: 30px;
text-align: center;
line-height: 40px;
transform: translateY(-50%);
cursor: pointer;
&:hover {
opacity: 0.5;
}
}
.carousel-ctrlPrev {
left: 5px;
}
.carousel-ctrlNext {
right: 5px;
}
(3)html
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>轮播图</title>
<link href="css/007.css" rel="stylesheet"> <!--记得替换-->
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="js/007.js" defer></script> <!--记得替换-->
</head>
<body>
<div class="container">
<!--carousel 轮播容器-->
<div class="carousel">
<!--carousel-inner 每一个轮播项内容-->
<div class="carousel-inner">
<div class="carousel-item active" data-index="0">
<a href="#">
<img class="carousel-img" src="img/1.png" alt="">
</a>
<div class="carousel-caption">
<h3>HEADER 1~</h3>
</div>
</div>
<div class="carousel-item" data-index="1">
<a href="#">
<img class="carousel-img" src="img/2.png" alt="">
</a>
<div class="carousel-caption">
<h3>HEADER 2~</h3>
</div>
</div>
<div class="carousel-item" data-index="2">
<a href="#">
<img class="carousel-img" src="img/3.png" alt="">
</a>
<div class="carousel-caption">
<h3>HEADER 3~</h3>
</div>
</div>
<div class="carousel-item" data-index="3">
<a href="#">
<img class="carousel-img" src="img/4.png" alt="">
</a>
<div class="carousel-caption">
<h3>HEADER 4~</h3>
</div>
</div>
<div class="carousel-item" data-index="4">
<a href="#">
<img class="carousel-img" src="img/5.png" alt="">
</a>
<div class="carousel-caption">
<h3>HEADER 5~</h3>
</div>
</div>
</div>
<!--carousel-indicators 指示器,指示当前显示的是第几项 也可以点击切换当前的显示项-->
<ul class="carousel-indicators">
<li class="active" data-index="0">1</li>
<li data-index="1">2</li>
<li data-index="2">3</li>
<li data-index="3">4</li>
<li data-index="4">5</li>
</ul>
<!--carousel-ctrl* 左右箭头,可上下切换当前的显示项-->
<span class="carousel-ctrlPrev"><</span>
<span class="carousel-ctrlNext">></span>
</div>
</div>
</body>
</html>