纯原生JS写封装左右无缝链接轮播图插件(完整代码及注释,可参考可直接使用)

(前言:小编也是一个刚入行的小白,所以写不出来多么高深的东西,若有错误欢迎指证或者其他的什么相互验证,但是不接受大神的鄙视,谢谢,转载请注明出路)

  1. 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等都可以进行自行更改自己喜欢的样式,只要不该元素结构以及类名等,当然如果你可以明白其中原理就都可以更改了)

  2. 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=`<div style="width:${(this.data.length+1)*this.width}px">`,strUl=`<ul>`,str;
            for(let i=0;i<this.data.length;i++){
                strDiv+=`<div><img src="${this.imgPrefix}${this.data[i].img}" width="${this.width}" height="${this.height}"></div>`;
                strUl+=`<li class="${i==0?'select':''}" style="width: ${this.width/800*12}px;height: ${this.width/800*12}px"></li>`
            }
            strDiv+=`<div><img src="${this.imgPrefix}${this.data[0].img}" width="${this.width}" height="${this.height}"></div>`;
            strDiv+=`</div>`;
            strUl+=`</ul>`
            //根据传入的是否需要左右按钮切换而判断是否需要添加左右按钮
            if(this.isArrow){str=strDiv+strUl+`<a class="leftBtn" style="width: ${this.width/800*50}px;height: ${this.width/800*50}px"></a><a class="rightBtn" style="width: ${this.width/800*50}px;height: ${this.width/800*50}px"></a>`}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使用了面向对象思想的类来进行的插件封装,可根据参数注释来进行自行调整)

  3. HTML

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <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一个插件对象进行传参即可)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值