插件描述
插件使用说明
- import插件
- 在html页面中书写一个容器(即调用插件时的形参1parent),给这个容器书写css样式,包括宽度和位置等
- 使用语句Carousel.createCarousel(parent,arr)生成轮播图.其中形参1是用来承载轮播图的容器,可以输入选择符字符串也可以输入节点;形参2是轮播图图片的src数组。
<script type="module">
import Carousel from "url"
Carousel.createCarousel(parent,arr)
</script>
插件编写思路
1.采用静态函数编写接口static createCarousel(parent,arr)
2.分析轮播图组成元素,需要一个轮播图容器(carousel_wrapper),一个可以装下两张图片的图片容器(img_wrapper),两个btn,跟图片个数相等的选项卡圆点;
3.将功能拆解:
- 图片预加载
- 创建轮播图元素
- 左右按钮的点击事件
- 添加需要参与下次轮播的图片进入img_wrapper
- 选项卡圆点的mouseover事件
- 更改选项卡圆点的样式
- 自动轮播
插件编写心得
- 函数式编程不仅仅是把代码写在一个个函数中被包裹,得注意每个函数尽可能单独完成一个唯一的功能,这样,元素的事件中就可以灵活的调用函数。
- 标志变量的使用非常重要。可以使用其作为开关,在程序中设置手动切换轮播图的开关,设置自动轮播的暂停与继续;也可以使用其作为逻辑分叉的判断条件
插件实现细节(部分)
if(typeof parent === "string") Carousel.parent=document.querySelector(parent);
Carousel.loadImg(Carousel.arr,Carousel.imgLoadedHandler)
Carousel.WIDTH = parseFloat(Carousel.list[0].width)
- 将第一张图片的宽高设置为carousel_wrapper的宽高
Carousel.createNextImg()
- 动态向img_wrapper中添加图片实现无缝轮播
height:${Carousel.HEIGHT}px
- 将形参1元素的高度动态设置为图片高度,解决高度塌陷问题
插件将carousel_wrapper设置了居中,即传入的形参1元素的水平中间,使得小像素显示屏也能显示大像素图片
注意事项
- 形参1parent代表的元素不需要任何的innerHTML,如果写了也会被插件清空
- 为了增强插件的稳定性,插件给形参1(parent)设置部分属性,如下
Object.assign(Carousel.parent.style,{
position:"relative",
height:`${Carousel.HEIGHT}px`,
zIndex:99999,
overflowX:"hidden"
});
- 左右按钮和选项卡圆点是固定尺寸的,适合较大的轮播图,如果图片较小可以手动修改其尺寸
插件源代码
export default class Carousel{
static prev;
static pos = 0;
static dots=[];
static time = 300;
static auto_play = true;
static isMoving = false;
static direction;
static speed = 20;
static parent;
static list=[];
static carousel_wrapper;
static WIDTH ;
static HEIGHT;
static go_left_btn;
static go_right_btn;
static img_wrapper;
static btn_list;
static screen_width;
static screen_height;
static arr;
//接口,导出插件生成的轮播图,用参数parent接受
static createCarousel(parent,arr){
Carousel.arr = arr;
Carousel.screen_width = window.innerWidth;
Carousel.screen_height = window.innerHeight;
Carousel.parent = parent;
if(typeof parent === "string") Carousel.parent=document.querySelector(parent);
Carousel.parent.innerHTML=""
Carousel.loadImg(Carousel.arr,Carousel.imgLoadedHandler);
}
//图片预加载
static imgLoadedHandler(list){
for(let i = 0;i < list.length;i++){
Carousel.list.push(list[i]);
}
Carousel.WIDTH = parseFloat(Carousel.list[0].width);
Carousel.HEIGHT = parseFloat(Carousel.list[0].height);
Object.assign(Carousel.parent.style,{
position:"relative",
height:`${Carousel.HEIGHT}px`,
zIndex:99999,
overflowX:"hidden"
});
Carousel.carousel_wrapper = Carousel.createCarouselWrapper();
Carousel.createImgWrapper(Carousel.carousel_wrapper);
Carousel.carousel_wrapper.addEventListener("mouseover",Carousel.mouseHandler);
Carousel.carousel_wrapper.addEventListener("mouseout",Carousel.mouseHandler);
Carousel.createBtn(Carousel.carousel_wrapper);
Carousel.createDots(Carousel.carousel_wrapper);
Carousel.go_left_btn.addEventListener("click",Carousel.clickHandler);
Carousel.go_right_btn.addEventListener("click",Carousel.clickHandler);
Carousel.autoPlay();
Carousel.img_wrapper.appendChild(Carousel.list[0]);
Carousel.parent.appendChild(Carousel.carousel_wrapper);
}
//创建轮播图外围容器
static createCarouselWrapper(){
let carousel_wrapper = Carousel.ce("div",{
width: `${Carousel.WIDTH}px`,
height:`${Carousel.HEIGHT}px`,
position:"absolute",
left:"50%",
marginLeft:`${-Carousel.WIDTH*0.5}px`,
overflowX:"hidden"
});
return carousel_wrapper;
}
//创建一个可以容纳两张图片的盒子
static createImgWrapper(parent,arr){
Carousel.arr = arr;
Carousel.img_wrapper = Carousel.ce("div",{
width: `${Carousel.WIDTH*2}px`,
height:`${Carousel.HEIGHT}px`,
position:"absolute",
left:0
},parent)
}
//创建两个按钮
static createBtn(parent){
Carousel.go_left_btn = new Image();
Carousel.go_left_btn.src="https://p2.lefile.cn/product/adminweb/2018/11/11/2a7f8349-14f0-42e1-afe8-7ae8afd54e1e.png";
Carousel.go_right_btn = new Image();
Carousel.go_right_btn.src="https://p2.lefile.cn/product/adminweb/2018/11/11/cae7b801-0fe6-4691-ba99-239ba9d11576.png";
Object.assign(Carousel.go_left_btn.style,{
position:"absolute",
left:`${Carousel.WIDTH*0.5-Carousel.screen_width*0.5}px`,
marginLeft:`100px`,
top:`${Carousel.HEIGHT*0.5}px`,
marginTop:`${-Carousel.go_right_btn.height*0.5}px`
})
Object.assign(Carousel.go_right_btn.style,{
position:"absolute",
left:`${Carousel.WIDTH*0.5-Carousel.screen_width*0.5+Carousel.screen_width}px`,
marginLeft:`-100px`,
top:`${Carousel.HEIGHT*0.5}px`,
marginTop:`${-Carousel.go_right_btn.height*0.5}px`
})
parent.appendChild(Carousel.go_left_btn)
parent.appendChild(Carousel.go_right_btn)
}
//创建圆点选项卡
static createDots(parent){
Carousel.dots = Carousel.ce("div",{
zIndex:66,
background:"red",
height:"30px",
width:"100%",
position:"absolute",
textAlign:"center",
bottom:"40px"
},parent);
Carousel.list.forEach((item,index)=>{
let span = Carousel.ce("span",{
display:"inline-block",
width:"30px",
height:"30px",
borderRadius:"50%",
background:"white",
marginRight:"5px"
},Carousel.dots)
span.addEventListener("mouseover",Carousel.dotMouseoverHandler);
span.span_index =index;
})
Carousel.prev = Carousel.dots.firstElementChild;
Carousel.prev.style.background = "blue";
}
//两个按钮的点击事件
static clickHandler(e){
if(Carousel.isMoving)return;
if(e.target === Carousel.go_right_btn)
{
Carousel.direction = "left";
Carousel.pos++;
if(Carousel.pos===Carousel.list.length)Carousel.pos=0;
}
else if(e.target === Carousel.go_left_btn){
Carousel.direction = "right";
Carousel.pos--;
if(Carousel.pos===-1)Carousel.pos=Carousel.list.length-1;
}
Carousel.createNextImg();
Carousel.animation();
Carousel.changeDot();
}
//从存储图片元素的数组之中调出轮播需要的一张图片,并将img_wrapper位置初始化
static createNextImg(){
if(Carousel.direction === "left"){
Carousel.img_wrapper.appendChild(Carousel.list[Carousel.pos]);
}else if(Carousel.direction === "right"){
Carousel.img_wrapper.insertBefore(Carousel.list[Carousel.pos],Carousel.img_wrapper.firstChild);
Carousel.img_wrapper.style.left=`${-Carousel.WIDTH}px`;
}
}
//图片移动动画
static animation(){
Carousel.isMoving = true;
if(Carousel.direction === "right"){
Carousel.img_wrapper.style.left = parseFloat(Carousel.img_wrapper.style.left)+Carousel.speed + "px";
if(parseFloat(Carousel.img_wrapper.style.left)<=0)
{
window.requestAnimationFrame(Carousel.animation);
}
else{
window.cancelAnimationFrame(Carousel.animation)
Carousel.img_wrapper.lastChild.remove();
Carousel.img_wrapper.style.left = 0;
Carousel.dot_index--;
Carousel.isMoving = false;
return;
}
}
else if(Carousel.direction === "left"){
Carousel.img_wrapper.style.left = parseFloat(Carousel.img_wrapper.style.left)-Carousel.speed + "px";
if(parseFloat(Carousel.img_wrapper.style.left)>=-(Carousel.WIDTH))
{
window.requestAnimationFrame(Carousel.animation);
}
else{
window.cancelAnimationFrame(Carousel.animation)
Carousel.img_wrapper.firstChild.remove();
Carousel.dot_index++;
Carousel.img_wrapper.style.left = 0;
Carousel.isMoving = false;
return;
}
}
}
//自动轮播
static autoPlay(){
if(Carousel.auto_play){
Carousel.time--;
if(Carousel.time<=0){
Carousel.time=300;
let evt = new Event("click");
Carousel.go_right_btn.dispatchEvent(evt);
}
}
window.requestAnimationFrame(Carousel.autoPlay)
};
//实现鼠标移入轮播图区域停止自动轮播,移出继续自动轮播
static mouseHandler(e){
if(e.type==="mouseover"){
Carousel.time=300;
Carousel.auto_play = false;
}
else if(e.type==="mouseout"){
Carousel.auto_play = true;
}
}
//选项卡中圆点的mouseover
static dotMouseoverHandler(e){
if(Carousel.isMoving)return;
if(e.target.constructor !== HTMLSpanElement)return;
if(Carousel.pos<e.target.span_index){
Carousel.direction = "left";
}
else if(Carousel.pos>e.target.span_index)
{
Carousel.direction = "right";
}
else return;
Carousel.pos = e.target.span_index;
Carousel.changeDot();
Carousel.createNextImg();
Carousel.animation();
}
//实现选项卡变化
static changeDot(){
if(Carousel.prev)Carousel.prev.style.background = "white";
Carousel.prev = Carousel.dots.children[Carousel.pos];
Carousel.prev.style.background = "blue";
}
//创建元素
static ce(type,style,parent){
let elem=document.createElement(type);
if(style){
Object.assign(elem.style,style);
}
if(parent){
if(typeof parent==="string")parent=document.querySelector(parent);
parent.appendChild(elem);
}
return elem;
}
//图片预加载
static loadImg(arr,callBack){
let img=new Image();
img.src=arr.shift();
img.arr=arr;
img.list=[];
img.callBack=callBack;
img.addEventListener("load",this.loadHandler);
}
static loadHandler(e){
let img=e.currentTarget;
img.list.push(img.cloneNode(false));
if(img.arr.length===0){
img.callBack(img.list);
return;
}
img.src=img.arr.shift();
}
}