面向对象编程js原生实现轮播图效果
1.先看效果图
2.需要实现的功能:
- 自动轮播
- 点击左右箭头按钮无缝轮播
- 点击数字按钮切换图片
分析:如何实现无缝轮播?
在一个固定大小的相框里有一个ul标签,其长度是几个图片宽度的总和,通过translateX()的方法来实现左右移动动画。
如何实现无缝呢?比如有三张图片,可以在把第一张图片通过cloneNode的方法克隆下来放到第三张图片后面。图片顺序 1,2,3,1,看下面的HTML结构,结构中并没有4张图,第四张图是生成的。
3.html结构
<!-- ul是图片盒子,ol是数字按钮盒子,最下面的div是左右箭头按钮盒子 -->
<div class="container">
<div id="screen">
<ul>
<li><img src="./img/1.jpg" alt=""></li>
<li><img src="./img/2.jpg" alt=""></li>
<li><img src="./img/3.jpg" alt=""></li>
</ul>
<ol>
<!--<li class="active">1</li>-->
<!--<li>2</li>-->
<!--<li>3</li>-->
</ol>
</div>
<div>
<span><</span>
<span>></span>
</div>
</div>
4.功能实现
4.1 创建对象
创建一个对象,需要传入一个相框盒子元素,通过这个元素来获取盒子中其他需要的元素,并把这些作为这个Carousel对象的属性:
function Carousel(el) {
this.screen = el; // 相框
this.width = this.screen.offsetWidth; // 相框宽度
this.ulBox = this.screen.children[0]; // ul盒子
this.list = this.ulBox.children; // ul下面所有li
this.olBox = this.screen.children[1]; // 数字按钮盒子
this.arrow = this.screen.nextElementSibling; // 箭头盒子
this.leftArraw = this.arrow.children[0]; // 左箭头
this.rightArraw = this.arrow.children[1]; // 右箭头
this.index = 0; // 数字按钮的索引
this.timeId = null; // 定时器的id
this.activeClass = 'active'; // 数字按钮class名
this.durtion = '.35s'; // 动画持续时间
}
4.2动画效果由translateX实现
// 动画
Carousel.prototype.animate = function (target) {
this.ulBox.style.transform = 'translateX(' + target + 'px)'
};
4.3根据轮播图片个数生成数字按钮节点
生成节点后,为新生成的节点添加点击事件,实现每次点击根据节点对应的index切换图片,这里实现的需求的第三个功能。
// 创建节点
Carousel.prototype.createNodes = function () {
let self = this;
// 创建按钮节点
for (let i = 0; i < self.list.length; i++) {
let liObj = document.createElement('li');
liObj.innerText = i + 1;
self.olBox.appendChild(liObj);
// 为生成的数字按钮添加点击事件
liObj.onclick = function () {
self.index = this.innerText - 1; // 获取当前点击对象的索引值
self.switch_sel();
self.animate(-self.index * self.width);
};
}
// 默认显示第一张图片,第一个数字按钮默认选中状态
self.olBox.children[0].className = self.activeClass;
// 克隆第一张图放到ulBox后面,实现无缝轮播
self.ulBox.appendChild(self.ulBox.children[0].cloneNode(true));
};
4.4轮播图数字按钮点击切换状态
因为多次用到这段代码,所有就写成一个方法挂在Carousel对象上了
// 切换数字按钮的选中状态
Carousel.prototype.switch_sel = function(){
let self = this;
for (let i = 0; i < self.olBox.children.length; i++) {
self.olBox.children[i].removeAttribute('class');
}
self.olBox.children[self.index].className = self.activeClass;
};
4.5轮播事件,也是点击右箭头的事件
// 轮播事件
Carousel.prototype.clickHandle = function () {
let self = this;
// 如果是最后一张图,直接跳到第一张
if (self.index === self.list.length - 1) {
self.index = 0;
// 当点击到最后一张时直接跳到第一张
self.ulBox.style.transitionDuration = '0s';
self.animate(-self.index * self.width);
}
// 必须有时间延迟,否则图片跳转切换不成功,因为self.animate()没有来得及执行就被后面的self.animate()函数覆盖了。
setTimeout(function () {
self.ulBox.style.transitionDuration = self.durtion;
self.index++;
self.animate(-self.index * self.width);
// 如果是最后一张图,则去掉最后一个的class属性,切换到第一个
if (self.index === self.list.length - 1) {
self.olBox.children[self.olBox.children.length - 1].removeAttribute('class');
self.olBox.children[0].className = self.activeClass;
} else { // 切换当前选中状态
self.switch_sel();
}
}, 20);
};
4.6事件绑定
为左右箭头点击绑定事件,同时当鼠标hover在相框上时自动轮播取消,鼠标离开相框时自动轮播开始执行。
// 事件绑定
Carousel.prototype.bindEvent = function () {
let self = this;
// 又点击下一张
self.rightArraw.onclick = function () {
self.clickHandle();
};
// 左点击上一张
self.leftArraw.onclick = function(){
if(self.index === 0){
self.index = self.list.length - 1;
// 直接跳到最后一张
self.ulBox.style.transitionDuration = '0s';
self.animate(-self.index * self.width);
}
setTimeout(function(){
self.ulBox.style.transitionDuration = self.durtion;
self.index--;
self.animate(-self.index * self.width);
self.switch_sel();
}, 20);
};
// 鼠标悬停清除定时器
self.screen.parentElement.onmouseover = function(){
self.timeId && clearInterval(self.timeId);
self.arrow.style.display = 'flex';
};
// 鼠标离开打开定时器
self.screen.parentElement.onmouseout = function(){
self.timeId = setInterval(self.clickHandle.bind(self), 2000);
self.arrow.style.display = 'none';
}
};
4.7初始化方法
初始化方法中创建节点,绑定事件,同时设定定时器实现自动轮播效果。
// 初始化
Carousel.prototype.init = function () {
this.createNodes();
this.bindEvent();
this.timeId = setInterval(this.clickHandle.bind(this), 2000);
// 注意这里要bind(this) 否则clickHandle中的this指向window
};
4.8实例化Carousel对象,大功告成
实例化一个轮播图对象,然后调该对象的init方法。
只要html结构相同,只需要传入不同的相框元素,就可以在同一个页面中实例化多个轮播图对象。也就是说,同一个页面的多处轮播效果。
let carousel = new Carousel(document.getElementById('screen'));
carousel.init();
5备注
全部的代码和css样式可参考我的github中的轮播图仓库,菜鸟程序猿一枚,程序设计如果有不妥的地方欢迎提出意见或建议,当然啦,如果你喜欢并star了我的这个仓库,我会很开心的 : )
[1]: https://github.com/jiangleiundo/carousel