(前言:小编也是一个刚入行的小白,所以写不出来多么高深的东西,若有错误欢迎指证或者其他的什么相互验证,但是不接受大神的鄙视,谢谢,转载请注明出路)
css
body,div,ul,li,a,p{
margin: 0;
padding: 0;
-webkit-user-select: none;
}
li{
list-style: none;
}
.Banner1{
margin: 20px auto;
overflow: hidden;
position: relative;
}
.Banner1>div:nth-of-type(1){
position: absolute;
}
.Banner1>div:nth-of-type(1)>div{
float: left;
}
.Banner1>ul{
position: absolute;
left: 42%;
bottom: 20px;
border-radius: 10px;
padding: 4px;
}
.Banner1>ul>li{
margin-left:1px;
float: left;
border-radius: 50%;
border: 1px solid #CCCCCC;
cursor: pointer;
}
.Banner1>ul>li.select{
background-color: #9ba0ad;
}
.Banner1>a{
position: absolute;
border-radius: 50%;
opacity: .8;
display: none;
cursor: pointer;
background-size: 100% 100%;
top: 45%;
}
.Banner1>a:nth-of-type(1){
left: 3%;
background: url("../img/左箭头-填充 (1).png") no-repeat ;
background-size: 100% 100%;
}
.Banner1>a:nth-of-type(2){
right: 3%;
background: url("../img/右箭头-填充.png") no-repeat;
background-size: 100% 100%;
}
(css中存放非宽高大小的样式,左右箭头图片以及li小按钮样式可以自行调整自己喜欢的样式,以及其他的left,bottom等都可以进行自行更改自己喜欢的样式,只要不该元素结构以及类名等,当然如果你可以明白其中原理就都可以更改了)
JS
~function () {
class Banner1{
// options是传入的参数对象,没传为空对象
constructor(options={}){
//解构传入的对象
let {
ele, //传入的容器对象
data,//需要绑定的json对象数据
url, //请求数据的API接口地址
isArrow=true, //是否支持左右切换
isFocus=true, //是否支持焦点切换
isAuto=true, //是否支持自动切换
interval=3000, //切换间隔速度
moveEnd, //切换完成后需要处理的事情
width=800, //ele的宽度,默认800px,必须是能整除20的数
height=400, //ele的高度,默认400px
imgPrefix='' //图片前缀
}=options;
// 将这些属性都挂载到实例中去
['ele', 'url', 'isArrow', 'isFocus', 'isAuto', 'interval', 'moveEnd','width','height','data','imgPrefix'].forEach(item => {
//item是一个字符串,而我们需要的是同名的变量,所以可以使用eval将字符串变成同名变量
this[item] = eval(item);
});
//调用init主入口开启轮播图
this.init();
}
//Bander的主入口init,规化方法的执行顺序
init(){
let p;
/**
* 浏览器的最大最小显隐会对setinterval定时器有暂停的影响,所以需要对浏览器的显隐进行处理
* document.onvisibilitychange监听浏览器窗口的显隐行为,最小化的时候其document.visibilityState属性会变成'hidden'
* 这个时候我们就要清楚掉定时器,不然后出现定时器乱了的现象,当再次显示浏览器窗口时就再将定时器加上
*/
document.onvisibilitychange= ()=> {
if(document.visibilityState==='hidden'){
clearInterval(this.times);
}else{
this.autoMove();
}
}
//传有数据就不在去请求数据了,没传才会去请求
if(!this.data){
//this.data没传就是undefined =》!fasle =true;就去请求数据
p=this.queryData();
}else{
//this.data传了有的话就不去请求数据了
p=new Promise((resolve, reject) =>{resolve()});
}
p.then(()=>{
//进行数据绑定
this.bindHtml()
},()=>{console.log('数据请求失败');return}).then(()=>{
if(this.isAuto){
this.autoMove();
}
if(this.eAs){
this.btnMove();
}
if(this.isFocus){
this.focusMove();
}
})
}
//请求数据
queryData(){
let {url}=this;
return new Promise((resolve,reject)=>{
let xhr=new XMLHttpRequest();
xhr.open('get',url);
xhr.onreadystatechange=()=>{
if(xhr.readyState===4&&xhr.status===200){
this.data=JSON.parse(xhr.responseText);
resolve();
}
if(xhr.status!=200){
reject();
}
}
xhr.send();
})
}
//绑定数据
bindHtml(){
//由于考虑到复用的效果,所以在绑定数据的同时将所以盒子的宽高都进行了一个计算添加,这样我们传入的宽高参数是多少,这个轮播图的整体大小就是多少,其中所有元素都会按比例进行缩放
//为父盒子添加样式(有部分不涉及宽高的样式就可以直接写在css中去,不需要动态生成)
this.ele.className="Banner1";
//为父盒子设置我们传进来的宽高
this.ele.style.width=/^(-)?\d+(\.\d+)?(px|rem|em)?$/.test(this.width)?/(px|rem|em)$/.test(this.width)?this.width:this.width+'px':'800px';
this.ele.style.height=/^(-)?\d+(\.\d+)?(px|rem|em)?$/.test(this.height)?/(px|rem|em)$/.test(this.height)?this.height:this.height+'px':'800px';
//生成模板字符串
let strDiv=`${(this.data.length+1)*this.width}px">`,strUl=``
,str;
for(let i=0;i<this.data.length;i++){
strDiv+=`${this.imgPrefix}${this.data[i].img}" width="${this.width}" height="${this.height}">`;
strUl+=`- ${i==0?'select':''}
" style="width: ${this.width/800*12}px;height: ${this.width/800*12}px">`
}
strDiv+=`${this.imgPrefix}${this.data[0].img}" width="${this.width}" height="${this.height}">`;
strDiv+=``;
strUl+=``
//根据传入的是否需要左右按钮切换而判断是否需要添加左右按钮
if(this.isArrow){str=strDiv+strUl+`${this.width/800*50}px;height: ${this.width/800*50}px">${this.width/800*50}px;height: ${this.width/800*50}px">`}else{str=strDiv+strUl}
//渲染页面
this.ele.innerHTML=str;
//获取到移动的div和所有的li以及两个左右按钮
this.eDiv=this.ele.getElementsByTagName('div')[0];
this.eLis=this.ele.getElementsByTagName('ul')[0].getElementsByTagName('li');
this.eAs=this.ele.getElementsByTagName('a');
//标识当前显示图片索引
this.liIndex=0;
//标识图片切换是否完成,避免上一次动画切换未完成用户又触发下一次动画
this.bool=false;
}
//自动轮播
autoMove(){
this.times=setInterval( ()=>{
let eLeft=parseFloat(getComputedStyle(this.eDiv)['left']),left=0;
let time=setInterval(()=>{
left-=this.width/800*20;
this.eDiv.style.left=eLeft+left+'px';
if(left<=-parseFloat(this.width)){
clearTimeout(time);
this.liIndex++;
if(this.liIndex===this.eLis.length){
this.liIndex=0;
this.eDiv.style.left='0px';
}
this.changeCss();
}
},this.width/800*17)
},this.interval)
//鼠标移入期间停止轮播
this.ele.onmouseover=()=>{
//显示左右小箭头
clearTimeout(this.times)
if(this.eAs){
[].forEach.call(this.eAs,(item)=>{
item.style.display='block';
})
}
}
//鼠标移出开始轮播
this.ele.onmouseout=()=>{
this.autoMove();
if(this.eAs){
[].forEach.call(this.eAs,(item)=>{
item.style.display='none';
})
}
}
}
//支持左右按钮切换
btnMove(){
for(let i=0;i<this.eAs.length;i++){
this.eAs[i].onclick=()=>{
if(this.bool) return;
this.bool=true;
//当单机左右按钮的时候,只需要清理定时器就可以,不需要再加上,因为按钮单机的时候会触发鼠标移入移出事件,鼠标移出事件会加上自动切换
clearInterval(this.times);
if(i===0) {
let eLeft = parseFloat(getComputedStyle(this.eDiv)['left']), left = 0;
eLeft=eLeft==0?(this.liIndex=this.eLis.length-1,this.eLis.length*-this.width):(this.liIndex-=1,eLeft);
let btnTime = setInterval(() => {
left += this.width/800*20;
this.eDiv.style.left = eLeft + left + 'px';
if (left >= this.width) {
clearInterval(btnTime);
this.changeCss();
this.bool=false;
}
}, this.width/800*17)
}else{
let eLeft = parseFloat(getComputedStyle(this.eDiv)['left']), left = 0;
let btnTime = setInterval(() => {
left -= this.width/800*20;
this.eDiv.style.left = eLeft + left + 'px';
if (left <= -this.width) {
clearInterval(btnTime);
this.liIndex++;
if(this.liIndex===this.eLis.length){
this.liIndex=0;
this.eDiv.style.left='0px';
}
this.changeCss();
this.bool=false;
}
}, this.width/800*17)
}
}
}
}
//支持焦点切换
focusMove(){
[].forEach.call(this.eLis,(item,index)=>{
item.onclick=()=>{
clearInterval(this.times)
if(this.liIndex===index)return;
this.liIndex=index;
this.eDiv.style.left=index*-this.width+'px';
this.changeCss();
}
})
}
//切换li样式
changeCss(){
[].forEach.call(this.eLis,(item,index)=>{
if(index!==this.liIndex){
item.className='';
}else{
item.className='select';
}
})
}
}
//挂载全局
window.Banner={
Banner1
};
}();
(JS使用了面向对象思想的类来进行的插件封装,可根据参数注释来进行自行调整)
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<link rel="stylesheet" href="xxx.css">
head>
<body>
<div id="box">div>
<script src="xxx.js">script>
<script>
let box=document.getElementById('box');
//将数据放入data
new Banner.Banner1({ele:box,
data:[
{img:'//img.alicdn.com/tps/TB1_2OWLVXXXXcTXVXXXXXXXXXX-1130-500.jpg'},
{img:'//img.alicdn.com/tps/TB1Lw9SLVXXXXajaXXXXXXXXXXX-1130-500.jpg'},
{img:'//img.alicdn.com/tps/TB1QyGZLVXXXXa9XVXXXXXXXXXX-1130-500.jpg'}]
,width:800,height:400});
//数据使用url请求得来
// new Banner.Banner1({ele:box,url:'../json/newList.json',width:800,height:400,imgPrefix:'../'});
script>
body>
html>
(html中引入上面的css以及js,然后new一个插件对象进行传参即可)