轮播图,效果如下
一、js文件
1.Utils类
export default class Utils{
static ce(type,style,parent){
var elem=document.createElement(type);
if(style){
for(var prop in style){
elem.style[prop]=style[prop];
}
}
if(typeof parent==="string") parent=document.querySelector(parent);
if(parent) parent.appendChild(elem);
return elem;
}}
2.LoadImage类
//声明LoadImage类继承EventTarget超类
export default class LoadImage extends EventTarget{
list; //预缓存的图片数组
num=0; //初始为0,每缓存一张照片,num++,用于遍历list内所有图片
finishArr=[]; //将预缓存图片潜复制后加入到finishArr
callBack; //调用时以参数形式传入的函数,可以对全部加载完成后的finishiArr进行操作。
static IMAGE_FINISH="imgFinish"; //为抛发事件设置常量事件名
//构造函数(list: 存放图片src的数组,basePath:图片路径的相同部分;expandedName:图片的后缀名,执行最后返回finishArr数组的函数)
constructor(list,basePath,expandedName,_callBack){
//继承超类EventTarget内容
super();
//判断第二个参数是不是函数,
if(basePath.constructor===Function)
{
//如果为函数,直接将参数内容赋给callBack
this.callBack=basePath;
//执行changeList函数,并把返回值赋予list
this.list=this.changeList(list)
}else{
//如果不是函数,参数还是原来顺序,并且执行changeList函数
this.callBack=_callBack;
this.list=this.changeList(list,basePath,expandedName)
}
//执行loadImage函数
this.loadImage();
}
//changeList函数:将图片地址整合为整体的地址
changeList(list,basePath,expandedName){
//如果基础地址存在,然后判断基础地址有无/ ,然后把基础地址跟list的图片名整合,最终存入list李表里
if(basePath){
basePath=basePath.endsWith("/") ? basePath : basePath+"/";
list=list.map(item=>basePath+item);
}
//如果后缀名存在
if(expandedName){
//遍历list,将list内的元素根据 . 分割
list=list.map(item=>{
var names=item.split(".")
//如果list内元素包含后缀名,直接返还,如果不包含,将expandedName加在元素后部
if(/jpg|png|jpeg|bmp|gif|webp/i.test(names[names.length-1])) return item;
return item+(expandedName.includes(".") ? expandedName : "."+expandedName);
})
}
//返还整合后的list
return list;
}
//缓存图片函数
loadImage(){
//将img实例化
var img=new Image();
//设置监听事件,如果未加载完成,执行loadHandler函数
this.loadFn=e=>this.loadHandler(e)
img.addEventListener("load",this.loadFn);
//加载图片路径,将图片缓存在浏览器里
img.src=this.list[this.num];
}
loadHandler(e){
//设置img为监听事件,即缓存的图片
var img=e.currentTarget;
//将图片浅复制,然后存入finishArr数组内
this.finishArr.push(img.cloneNode(false));
//通过num 遍历整个list数组,将图片所有路径依次加载一遍。即将所有图片都缓存到浏览器内,并且将所有图片浅复制后放入finishArr数组内。
this.num++;
//如果num超出数组长度,即所有图片都加载完成后,删除监听事件,监听函数置为null
if(this.num>this.list.length-1){
img.removeEventListener("load",this.loadFn);
this.loadFn=null;
//如果callBack参数存在,通过callBack函数对finishArr进行操作。
if(this.callBack){
this.callBack(this.finishArr);
}
// 如果不存在,设置事件抛发
else{
var evt=new Event(LoadImage.IMAGE_FINISH);
evt.list=this.finishArr;
this.dispatchEvent(evt);
}
return;
}
//给图片赋予新路径,进而将图片缓存到浏览器内。触发加载事件
img.src=this.list[this.num];
}
}
3.Carousel类
import LoadImage from "./LoadImage.js";
import Utils from "./Utils.js";
export default class Carousel {
imgList; //轮播图图片放入ingList数组中
w;
h;
bnlist; //存放左右点击按钮的图片
list; //存放只含有轮播图图片的数组
imageCon; //存放两张图片隐藏在轮播图后边,通过调整定位改变位置,进而实现轮播图
parent; //父元素
dot; //轮播图下部点击小圆点整体ul图
dotList = []; //轮播图下部点击小圆点li存入数组
pos = 0; //通过pos 记录当前为第几张图片
direction = ""; //记录轮播图转换时图片移动方向
bool = false; //控制图片是否转换,转换开关
x = 0; //控制imageCon left的值
speed = 0.5; // 控制imageCon移动速度
autoBool = false; //图片自动轮播开关
time = 200; //设置防抖 200次执行一次
pre; //设置下部小圆点 背景颜色透明度
static carouselList = []; //存放轮播图,可以设置多个轮播图,然后添加到数组内
constructor(_imgList) {
this.imgList = _imgList;
//创建播放轮播图的div
this.carousel = this.createCarousel();
//预缓存图片,并且全部缓存完成后执行finishHandler函数,此时图片已经是一个图片元素了
new LoadImage(_imgList, (list) => this.finishHandler(list));
//将创建的轮播图放入静态数组内
Carousel.carouselList.push(this);
}
//将元素放入给定的父元素内
appendTo(parent) {
if (parent.constructor === String) parent = document.querySelector(parent);
parent.appendChild(this.carousel);
this.parent = parent;
}
//图片全部预缓存结束后执行的函数
finishHandler(_list) {
//将预缓存后存放浅复制图片的数组删除后两位,即删除左右按钮两张图片,将删除的两张图片存入新数组内
this.bnlist = _list.splice(-2);
//如果w不存在,给w赋予轮播图第一张图片的宽和高
if (!this.w) {
this.w = _list[0].width / 100;
this.h = _list[0].height / 100;
}
// 到此为止w和h正式全部确认完毕
this.list = _list.map((item) => {
item.style.width = this.w + "rem";
item.style.height = this.h + "rem";
return item;
});
//给carousel设置宽高
Object.assign(this.carousel.style, {
width: this.w + "rem",
height: this.h + "rem",
});
//图片全部加载完成后执行以下函数
this.createImageCon();
this.createBn();
this.createDot();
this.changePre();
}
//setWH函数 :设置图片宽高
setWH(_w, _h) {
//如果图片加载完成,直接返回
if (!this.parent) return;
//如果传入的参数为布尔值
if (_w.constructor === Boolean) {
//如果第一个为true
if (_w) {
//则以父元素的宽作为图片的宽,高为宽的一半
var rect = this.parent.getBoundingClientRect();
this.w = rect.width / 100;
this.h = this.w / 3;
}
//如果第一个参数为数值型,宽高为 传入的参数
} else if (_w.constructor === Number) {
this.w = _w / 100;
this.h = _h / 100;
}
}
//创建轮播图容器
createCarousel() {
var carousel = Utils.ce("div", {
position: "relative",
margin: "auto",
overflow: "hidden",
left: 0,
right: 0,
backgroundColor: "rgba(255,0,0,0.1)",
});
//为轮播图容器设置鼠标滑入和鼠标滑出事件,用来实现 轮播图自动播放
carousel.addEventListener("mouseenter", (e) => this.mouseHandler(e));
carousel.addEventListener("mouseleave", (e) => this.mouseHandler(e));
return carousel;
}
//创建图片存放的div,存放两张图片,以实现图片实现
createImageCon() {
this.imageCon = Utils.ce("div", {
width: this.w * 2 + "rem",
height: this.h + "rem",
position: "absolute",
left: 0,
});
//将第一张图片放入图片存放容器中
this.imageCon.appendChild(this.list[0]);
//将图片存放容器放入轮播图div中
this.carousel.appendChild(this.imageCon);
}
//创建左右按钮
createBn() {
//遍历存放左右按钮的数组,并且给图片元素添加CSS样式
this.bnlist.forEach((item, index) => {
Object.assign(item.style, {
position: "absolute",
left: index === 0 ? "20px" : "none",
right: index === 1 ? "20px" : "none",
top: (this.h - item.height / 100) / 2 + "rem",
});
//给左右按钮添加点击事件
item.addEventListener("click",e => this.clickHandler(e));
//将左右按钮添加到轮播图容器里
this.carousel.appendChild(item);
});
}
createDot() {
//创建存放轮播图下方小按钮的ul
this.dot = Utils.ce("ul", {
listStyle: "none",
margin: "0px",
padding: "0px",
position: "absolute",
bottom: "0.2rem",
});
//根据存放图片数组的长度创建小按钮li
this.list.forEach((item, index) => {
var li = Utils.ce(
"li",
{
width: "0.15rem",
height: "0.15rem",
backgroundColor: "rgba(255,0,0,0)",
border: "1px solid #FF0000",
borderRadius: "0.15rem",
float: "left",
marginLeft: index === 0 ? 0 : "0.1rem",
},
this.dot
);
//将创建的li放入dotList数组内
this.dotList.push(li);
});
//将小按钮添加到轮播图容器内
this.carousel.appendChild(this.dot);
//给小按钮设置位置
this.dot.style.left = (this.w - this.dot.offsetWidth / 100) / 2 + "rem";
//给小按钮添加点击事件
this.dot.addEventListener("click", (e) => this.clickDotHandler(e));
}
//左右按钮触发后执行的函数
clickHandler(e) {
if(this.bool) return;
//如果侦听的元素为左右按钮数组内的第0为 即左按钮时
if (this.bnlist.indexOf(e.currentTarget) === 0) {
//pos-1,pos为轮播图图片的“编号”,图片依靠pos改变。
this.pos--;
//如果pos小于零说明左侧没有图片了,pos等于最右侧图片“编号”
if (this.pos < 0) this.pos = this.list.length - 1;
//图片此时向右滑动
this.direction = "right";
}
//else即为右按钮
else {
//pos的值+1
this.pos++;
//如果pos大于了图片的个数,则右侧没有图片了,pos等于最左侧图片的“编号”,即0
if (this.pos > this.list.length - 1) this.pos = 0;
//此时pos向左移动
this.direction = "left";
}
//然后执行图片切换函数
this.createNextImage();
}
//点击下方小按钮执行的函数
clickDotHandler(e) {
if(this.bool) return;
//委托事件,如果点击的元素不是li,直接返回
if (e.target.constructor !== HTMLLIElement) return;
//声明index为点击的li在数组内的下标
var index = this.dotList.indexOf(e.target);
//如果点击li的下标等于当前pos,即小按钮对应的图片一致时,直接返回
if (index === this.pos) return;
//根据下标和pos的大小判断点击li后图片应该左移还是右移
this.direction = index > this.pos ? "left" : "right";
//然后将pos改为点击li的下标
this.pos = index;
//执行更换图片的函数
this.createNextImage();
}
//更换图片函数
createNextImage() {
//如果移动方向为左
if (this.direction === "left") {
//将在图片列表里下标为pos的图片元素插入到存放图片用来转换的容器内
this.imageCon.appendChild(this.list[this.pos]);
this.imageCon.style.left = "0rem";
this.x = 0;
}
//如果移动方向为右
else {
//在转换容器的最左侧插入下标为pos的图片元素
this.imageCon.insertBefore(this.list[this.pos], this.imageCon.firstChild);
//然后将给转换容器定位为-w ,即把准备切换的图片切换到最左侧,以实现切换动画效果
this.imageCon.style.left = -this.w + "rem";
//x赋值为-w
this.x = -this.w;
}
//将切换开关设置为true
this.bool = true;
//执行下方按钮背景图改变函数
this.changePre();
}
changePre() {
//如果pre存在,先把所有小圆点背景色设为透明
if (this.pre) {
this.pre.style.backgroundColor = "rgba(255,0,0,0)";
}
//然后给pre赋值为下标为pos的小圆点,并且将其背景色设置为0.6透明
this.pre = this.dotList[this.pos];
this.pre.style.backgroundColor = "rgba(255,0,0,0.6)";
}
//鼠标滑入滑出事件执行的函数
mouseHandler(e) {
//如果鼠标滑入,自动播放关闭,且防抖time设为200
if (e.type === "mouseenter") {
this.autoBool = false;
this.time = 200;
} else {
//如果鼠标滑出,开始自动播放
this.autoBool = true;
}
}
//改变函数
update() {
this.imgMove();
this.autoPlay();
}
//图片转换函数
imgMove() {
//判断容器是否移动,否的话直接返回
if (!this.bool) return;
//如果移动方向为左
if (this.direction === "left") {
//x值逐渐减少,即容器定位左移,显示图片左移效果
this.x -= this.speed;
//当x<=-w时,x=0,关闭转换开关,,并且删除第一张在转换容器的图片
if (this.x <= -this.w) {
this.x = 0;
this.bool = false;
this.imageCon.firstElementChild.remove();
}
//转换容器定位到x
this.imageCon.style.left = this.x + "rem";
} else {
//右移时,x值从-w逐渐增大,即容器右移,图片右移效果
this.x += this.speed;
//当x>=0时,x=0,关闭转换开关,删除之前图片
if (this.x >= 0) {
this.x = 0;
this.bool = false;
this.imageCon.lastElementChild.remove();
}
//转换容器定位到x=0
this.imageCon.style.left = this.x + "rem";
}
}
//自动播放函数
autoPlay() {
//如果开关为关,即鼠标滑入,直接返回
if (!this.autoBool) return;
this.time--;
//如果开关为开,即鼠标滑出,抛发给右按钮点击事件
if (this.time > 0) return;
this.time = 200;
var evt = new MouseEvent("click");
this.bnlist[1].dispatchEvent(evt);
}
//静态改变方法,可以给全部的轮播图实现改变
static UPDATE() {
for (var i = 0; i < Carousel.carouselList.length; i++) {
Carousel.carouselList[i].update();
}
}
}
二、html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
html
{
font-size: 100px;
}
body
{
font-size: 16px;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<script type="module">
import Carousel from "./js/Carousel.js";
//设置浏览框改变事件
window.addEventListener("resize",resizeHandler);
animation();
var arr=["./img/a.png","./img/b.png","./img/c.png","./img/d.png","./img/e.png","./img/left.png","./img/right.png"];
var arr1=["./img/a.jpeg","./img/b.jpeg","./img/c.jpeg","./img/d.jpeg","./img/e.jpeg","./img/left.png","./img/right.png"];
//实例化轮播图1对象
let carousel=new Carousel(arr);
//将轮播图添加到body里
carousel.appendTo("body");
//图片的宽高等于父元素容器的宽高
carousel.setWH(true);
//实例化轮播图2对象
let carousel1=new Carousel(arr1);
//将轮播图添加到body里
carousel1.appendTo("body");
//将图片大小设置为固定大小
carousel1.setWH(600,200);
//动画函数
function animation(){
requestAnimationFrame(animation);
//所有轮播图都执行静态UPDATE函数
Carousel.UPDATE();
}
//改变html内部元素大小,实现浏览框缩小放大时,轮播图跟着缩小放大
function resizeHandler(e){
document.documentElement.style.fontSize=document.documentElement.clientWidth*(100/screen.width)+"px";
}
</script>
</body>
</html>