JavaScript面向对象实现自适应轮播图
作者:闭包旅人时间:2026-10-25 08:30:22浏览:463
本文介绍使用JavaScript面向对象方式实现的轮播图组件。支持自动轮播、鼠标悬停暂停、左右按钮及底部指示器切换。具备自适应能力,可指定父容器或默认占满屏幕,宽高可配置。通过传入图片数据创建实例,结合requestAnimationFrame实现平滑动画效果。
本文分享了一个使用JavaScript编写的轮播图完整示例,供读者参考学习。
主要功能包括:
1. 自动轮播:当鼠标悬停在轮播区域时停止切换,鼠标移开后恢复自动播放。
2. 左右导航:点击左右箭头按钮可手动切换图片。
3. 底部指示器:点击下方的圆点按钮可跳转至对应图片。
4. 尺寸自适应:
支持嵌入指定的父容器中显示。
若未指定父容器,则默认挂载至body标签,宽度占满整个屏幕。当浏览器窗口大小改变时,轮播图尺寸按比例缩放。
允许自定义设置轮播图的宽度和高度。
实现思路:采用面向对象编程模式。使用时需传入图片列表及相关数据,随后创建实例即可使用。
import Carousel from './js/Carousel.js';
var itemList1 = [{
day: 26,
date: "/Oct.2020",
title: "秘境之蓝 无阿里不西藏 自驾阿里小北线",
src: "./carousel_img/a.jpg",
},
{
day: 25,
date: "/Oct.2020",
title: "这是一个什么样的国家?",
src: "./carousel_img/b.jpg",
},
{
day: 24,
date: "/Oct.2020",
title: "在徽州,给秋天写了8封信",
src: "./carousel_img/c.jpg",
},
{
day: 23,
date: "/Oct.2020",
title: "「穿过狂野的风」赶赴内蒙的追羊计划",
src: "./carousel_img/d.jpg",
},
{
day: 22,
date: "/Oct.2020",
title: "爱让我们无所不能|南极大冒险",
src: "./carousel_img/e.jpg",
},
];
let carousel1 = new Carousel(itemList1);
carousel1.appendTo(".div1");
animation();
function animation(){
requestAnimationFrame(animation);
carousel1.update();
// carousel2.update();
}核心代码实现如下:
import Component from './Component.js';
export default class Carousel extends Component{
imgList;
bnList;
imgCon;
dot;
dotList=[];
data;
direction;
pos=0;
x=0;
speedX=1;
bool=false;
time=200;
autoBool=true;
// WIDTH=13.66;
// HEIGHT=4.55;
WIDTH;
HEIGHT;
constructor(_data,_width,_height){
super("div");
this.data=_data;
this.width = _width;
this.height = _height;
this.elem.className = "carousel";
// Object.assign(this.elem.style,{
// width:this.WIDTH+"rem",
// height:this.HEIGHT+"rem",
// position:"relative",
// overflow:"hidden",
// });
let arr = ["./carousel_img/left.png","./carousel_img/right.png"];
let _imgList = this.data.reduce((value,item)=>{
if(item.src) value.push(item.src);
return value
},arr);
this.loadImg(_imgList,this.createCarousel);
// window.addEventListener("resize",e=>this.resizeHandler(e));
}
createCarousel(imgList){
Object.assign(this.elem.style,{
width:this.WIDTH+"rem",
height:this.HEIGHT+"rem",
position:"relative",
overflow:"hidden",
});
this.imgList = imgList;
this.bnList = this.imgList.splice(0,2);
imgList.forEach(item=>{
Object.assign(item.style,{
width:this.WIDTH+"rem",
height:this.HEIGHT+"rem",
})
})
this.createimgCon();
this.createDotList();
this.createBn();
// 动画一般在外面做,类里面只需要写状态更新即可。
// this.animation();
// 鼠标停留在轮播图上时不进行自动轮播。
this.elem.addEventListener("mouseenter",e=>this.mouseHandler(e));
this.elem.addEventListener("mouseleave",e=>this.mouseHandler(e));
}
createimgCon(){
this.imgCon = document.createElement("div");
Object.assign(this.imgCon.style,{
width:this.WIDTH*2+"rem",
height:this.HEIGHT+"rem",
position:"absolute",
});
let item = this.createItem(this.imgList[0],this.data[0]);
this.imgCon.appendChild(item);
this.elem.appendChild(this.imgCon);
}
createItem(img,obj){
let item = document.createElement("div");
Object.assign(item.style,{
width:this.WIDTH+"rem",
height:this.HEIGHT+"rem",
position:"relative",
float:"left",
});
let title = document.createElement("div");
Object.assign(title.style,{
position:"absolute",
left:"15%",
top:"0.3rem",
fontSize:"0.3rem",
color:"#ffffff",
textShadow:"0.02rem 0.02rem 0.02rem #000000",
width:"8rem",
lineHeight:"0.5rem",
})
let head1=document.createElement("div");
Object.assign(head1.style,{
height:"0.5rem",
})
head1.textContent = obj.date;
let span = document.createElement("span");
Object.assign(span.style,{
fontSize:"0.4rem",
});
span.textContent = obj.day;
let head2 = document.createElement("div");
Object.assign(head2.style,{
height:"0.5rem",
})
head2.textContent = obj.title;
head1.insertBefore(span,head1.firstChild);
title.appendChild(head1);
title.appendChild(head2);
item.appendChild(title);
item.appendChild(img);
return item;
}
createDotList(){
this.dot = document.createElement("ul");
Object.assign(this.dot.style,{
listStyle:"none",
margin:0,
padding:0,
position:"absolute",
left:(this.WIDTH-1.8)/2+"rem",
bottom:"0.3rem",
})
for(let i=0;i<this.imgList.length;i++){
let li = document.createElement("li");
Object.assign(li.style,{
width:"0.18rem",
height:"0.18rem",
borderRadius:"0.2rem",
marginLeft:i===0?"0px":"0.2rem",
border:"0.02rem solid red",
float:"left",
})
this.dot.appendChild(li);
this.dotList.push(li);
}
this.dot.addEventListener("click",e=>this.dotClickHandler(e));
this.elem.appendChild(this.dot);
}
createBn(){
for(let i=0;i<this.bnList.length;i++){
Object.assign(this.bnList[i].style,{
position:"absolute",
top:(this.HEIGHT*100-this.bnList[i].height)/2/100+"rem",
})
if(i===0){
this.bnList[i].style.left = "0.5rem";
}else{
this.bnList[i].style.right = "0.5rem";
}
this.bnList[i].addEventListener("click",e=>this.bnClickHandler(e));
this.elem.appendChild(this.bnList[i]);
}
}
bnClickHandler(e){
if(this.bool) return
if(e.target===this.bnList[0]){
this.direction="left";
this.pos++;
if(this.pos>this.imgList.length-1) this.pos = 0;
}else{
this.direction="right";
this.pos--;
if(this.pos<0) this.pos=this.imgList.length-1;
}
this.bool=true;
this.createNextItem();
}
dotClickHandler(e){
if(e.target.constructor!==HTMLLIElement) return //这里因为是对父元素进行侦听,因此要先判断点击的是不是li,如果点击的不是小圆点就不能改变开关,直接return。不能先改变开关。
if(this.bool)return
for(let i=0;i<this.dotList.length;i++){
if(e.target===this.dotList[i]){
if(this.pos===i) return
this.direction=i<this.pos?"right":"left";
this.pos=i;
}
}
this.bool=true;
this.createNextItem();
}
createNextItem(){
let nextItem=this.createItem(this.imgList[this.pos],this.data[this.pos]);
if(this.direction==="left"){
this.imgCon.appendChild(nextItem);
this.x=0;
}else{
this.imgCon.insertBefore(nextItem,this.imgCon.firstChild);
this.x=-this.WIDTH;
}
this.imgCon.style.left=this.x+"rem";
}
update(){
this.imgMove();
this.autoPlay();
}
// 这里只需要做一个状态更新即可。
// 动画在外面做。
// animation(){
// requestAnimationFrame(this.animation);
// if(!this.bool) return
// this.imgMove();
// }
imgMove(){
if(!this.bool) return
if(this.direction==="left"){
this.x-=this.speedX;
if(this.x<-this.WIDTH){
this.imgCon.firstElementChild.remove();
this.x=0;
this.bool=false;
}
}else{
this.x+=this.speedX;
if(this.x>0){
this.imgCon.lastElementChild.remove();
this.x=0;
this.bool=false;
}
}
this.imgCon.style.left=this.x+"rem";
}
autoPlay(){
if(!this.autoBool) return
this.time--; //增加防抖
if(this.time===0){
let evt = new Event("click");
this.bnList[0].dispatchEvent(evt);
this.time=200;
}
}
resizeHandler(e){
document.documentElement.style.fontSize=document.documentElement.clientWidth/(this.WIDTH*100)*100+"px";
}
appendTo(parent){
if(typeof parent==="string") parent = document.querySelector(parent);
parent.appendChild(this.elem);
if(!isNaN(this.WIDTH) && !isNaN(this.HEIGHT)) return
if(parent===document.body){
this.WIDTH = 13.66;
this.HEIGHT = 4.55;
}else{
let rect = parent.getBoundingClientRect();
this.WIDTH=rect.width/100;
this.HEIGHT=rect.height/100;
}
}
mouseHandler(e){
if(e.type==="mouseenter"){
this.autoBool=false;
}else{
this.autoBool=true;
}
}
// 图片预加载
loadImg(_imgList,_callBack){
let img = new Image();
img.i=0;
img.arr=[];
img.imgList=_imgList;
// img.callBack=_callBack;
img.src=_imgList[img.i];
img.addEventListener("load",e=>this.imgLoadFinishHandler(e));
}
imgLoadFinishHandler(e){
// console.log(e.currentTarget);
e.currentTarget.arr.push(e.currentTarget.cloneNode());
e.currentTarget.i++;
if(e.currentTarget.i<e.currentTarget.imgList.length){
e.currentTarget.src = e.currentTarget.imgList[e.currentTarget.i];
}else{
// e.currentTarget.callBack(e.currentTarget.arr);
this.createCarousel(e.currentTarget.arr);
}
}
}以上就是本文的全部内容,希望能为读者的学习提供有益帮助,欢迎继续支持本站。
作者最新文章
什么时候该用JS构造器:与工厂模式、字面量的选择对比
2026-11-05 16:18:22
推荐几款轻量级JS照片墙开源库及对比
2026-11-05 15:56:19
JavaScript递归写法有哪些常见陷阱及避免方法
2026-11-05 14:53:38
JS数组浅拷贝与深拷贝怎么选?场景与方法总结
2026-11-05 14:41:02
p5.js 中 setup() 和 draw() 函数的执行机制详解
2026-11-05 12:32:38
