原生JS无缝轮播

需求:

1. 点击左右箭头切换图片

2. 点击标题切换对应的图片

3. 实现无缝循环切换 (所谓无缝轮播就是最后一张图片和第一张图片连接起来,实际上是给我们造成一种视觉假象)

4. 封装函数,方便以后使用

 

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6     <title>Document</title>
  7     <style>
  8         .box{width: 1130px;height: 300px;margin: 20px auto;position: relative;
  9             overflow: hidden;
 10         }
 11         .imgbox{height: 300px;position: absolute;left:0;}
 12         .imgbox a{float: left;}
 13         .imgbox img{width: 1130px;height: 300px;}
 14 
 15     </style>
 16 </head>
 17 <body>
 18     <div class="box">
 19         <div class="imgbox">
 20             <a><img src="https://img.zcool.cn/community/013c185ec5e1a0a801214d72ae5567.jpg" alt=""></a>
 21             <a><img src="https://img.zcool.cn/community/019b5a5ec5ea6ba801209b864afbad.png" alt=""></a>
 22             <a><img src="https://img.zcool.cn/community/0155475ec5ea82a801209b86526dc0.png" alt=""></a>
 23             <a><img src="https://img.zcool.cn/community/0133395ec5ea9fa801209b86533992.png" alt=""></a>
 24             <a><img src="https://img.zcool.cn/community/013c185ec5e1a0a801214d72ae5567.jpg" alt=""></a>
 25         </div>
 26     </div>
 27 </body>
 28 <script>
 29     // 可自定义的轮播图
 30     class Banner{
 31         constructor(ops){
 32             // 处理参数
 33             this.imgbox = ops.imgbox;
 34             this.list = ops.list!==false ? true : false;
 35             this.btn = ops.btn!==false ? true : false;
 36             this.autoPlay = ops.autoPlay!==false ? true : false;
 37             // 默认索引
 38             this.index = 0;
 39             // 获取所有图片
 40             this.items = this.imgbox.children;
 41 
 42             // 功能1. 初始化布局:完善imgbox的宽度
 43             this.init();
 44             // 功能B. 根据参数决定是否创建按键
 45             this.isBtn();
 46             // 功能L. 根据参数决定是否创建list
 47             this.isList();
 48             // 功能A. 根据参数决定是否需要自动播放
 49             this.isAutoPlay();
 50         }
 51         init(){
 52             this.imgbox.style.width = this.items.length * this.items[0].offsetWidth + "px";
 53         }
 54         isAutoPlay(){
 55             // A1.如果是false,终止当前函数,不执行后面代码,不做这个功能
 56             if(!this.autoPlay) return;
 57             // 如果执行到此处,说明上面过来的是true,没有执行return
 58 
 59             // A2.立即开启计时器,执行点击右按钮要做的事情
 60             this.t = setInterval(() => {
 61                 // 右按钮被点击时要执行的函数
 62                 this.changeIndex(-1);
 63             }, 2000);
 64 
 65             var that = this;
 66             // A3.鼠标进入停止
 67             this.imgbox.parentNode.onmouseover = function(){
 68                 clearInterval(that.t);
 69             }
 70             // A4.鼠标离开继续
 71             this.imgbox.parentNode.onmouseout = function(){
 72                 that.t = setInterval(() => {
 73                     that.changeIndex(-1);
 74                 }, 2000);
 75             }
 76         }
 77         isList(){
 78             // L1.如果是false,终止当前函数,不执行后面代码,不做这个功能
 79             if(!this.list) return;
 80             // 如果执行到此处,说明上面过来的是true,没有执行return
 81 
 82             // L2.为了实现无缝轮播,将第一张图复制了一遍多了一张,记得去掉
 83             var num = this.items.length-1;
 84             // 假设的图片的名字,将来必然是数据
 85             var arr = ["体彩","彩墨画","洗剪吹","网页设计"];
 86             // L3.创建list的容器
 87             this.list = document.createElement("div");
 88             this.list.style.cssText = `position: absolute;width: 100%;height: 40px;line-height: 40px;display: flex;bottom: 0;left:0;text-align: center;`;
 89             // L4.根据图片的数量,创建对应个span
 90             var str = "";
 91             for(var i=0;i<num;i++){
 92                 str += `<span key=${i} style="flex: 1;margin: 0 1px;background: rgba(200,200,200,0.6)">${arr[i]}</span>`;
 93             }
 94             // L5.将span放在list容器中
 95             this.list.innerHTML = str;
 96             // 设置索引对应span的当前项
 97             this.list.children[this.index].style.background = "green";
 98             // L6.将list容器插入页面
 99             this.imgbox.parentNode.appendChild(this.list);
100 
101             // L7.绑定list中span的事件
102             this.listAddEvent();
103         }
104         listAddEvent(){
105             var that = this;
106             var aspan = this.list.children;
107             for(var i=0;i<aspan.length;i++){
108                 aspan[i].onclick = function(){
109                     // L8.获取span身上的索引:保证索引的数据是数值,防止将来出现问题
110                     that.index = parseInt(this.getAttribute("key"));
111                     // L9.执行move,显示对应图片
112                     that.move();
113                     // L11.修改当前背景色
114                     that.setActive()
115                 }
116             }
117         }
118         setActive(){
119             // 取消所有
120             for(var i=0;i<this.list.children.length;i++){
121                 this.list.children[i].style.background = "rgba(200,200,200,0.6)";
122             }
123             // 为了处理最后一张图(其实就是复制的第一张图)的索引,单独判断,保存变量
124             // 计算索引
125             var k = this.index===this.items.length-1 ? 0 : this.index;
126             // 设置当前索引对应的span的背景色
127             this.list.children[k].style.background = "green";
128         }
129         isBtn(){
130             // B1.如果是false,终止当前函数,不执行后面代码,不做这个功能
131             if(!this.btn) return;
132             // 如果执行到此处,说明上面过来的是true,没有执行return
133 
134             // B2.创建并插入左按钮
135             this.left = document.createElement("input");
136             this.left.style.cssText = `width: 40px;height: 40px;background: rgba(200,200,200,0.6);border:none;position: absolute;top:130px;left:0`;
137             this.left.value = "<"
138             this.imgbox.parentNode.appendChild(this.left);
139             
140             // 创建并插入右按钮
141             this.right = document.createElement("input");
142             this.right.style.cssText = `width: 40px;height: 40px;background: rgba(200,200,200,0.6);border:none;position: absolute;top:130px;right:0`;
143             this.right.value = ">";
144             this.imgbox.parentNode.appendChild(this.right);
145 
146             this.left.type = this.right.type = "button";
147 
148             // B3.绑定左右按钮的点击事件
149             this.btnAddEvent();
150         }
151         btnAddEvent(){
152             var that = this;
153             this.left.onclick = function(){
154                 // B4-1.改变索引
155                 that.changeIndex(1)
156             }
157             this.right.onclick = function(){
158                 // B4-2.改变索引
159                 that.changeIndex(-1);
160             }
161         }
162         changeIndex(d){
163             if(d===1){
164                 if(this.index===0){
165                     this.index = this.items.length-2;
166                     this.imgbox.style.left = -(this.items.length-1) * this.items[0].offsetWidth + "px";
167                 }else{
168                     this.index--;
169                 }
170             }else{
171                 if(this.index===this.items.length-1){
172                     this.index = 1;
173                     this.imgbox.style.left = 0;
174                 }else{
175                     this.index++;
176                 }
177             }
178             // B5.移动大框,切换图片
179             this.move();
180             // L12.点击按钮时,设置索引对应的list的span的背景色
181             // 设置之前先判断,list出否存在,不存在,不设置样式
182             this.list && this.setActive();
183         }
184         move(){
185             // B6.显示图片
186             // L10.显示图片
187             // 神器:console.log
188             // console.log(this.index);
189             move(this.imgbox, {left: -this.index*this.items[0].offsetWidth});
190         }
191     }
192 
193     // 准备执行方式
194     new Banner({
195         imgbox:document.querySelector(".box .imgbox"),  // 必传
196         list:true,         // 可选,默认为true
197         btn:true,          // 可选,默认为true
198         autoPlay:false      // 可选,默认为true
199     })
200 
201 
202     function move(ele, data, cb) {
203         clearInterval(ele.t);
204         ele.t = setInterval(() => {
205             var onoff = true;
206 
207             for (var i in data) {
208                 var iNow = parseInt(getStyle(ele, i));
209 
210                 var speed = (data[i] - iNow) / 8;
211                 speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
212 
213                 ele.style[i] = iNow + speed + "px";
214 
215                 if (iNow != data[i]) {
216                     onoff = false;
217                 }
218             }
219             if (onoff) {
220                 clearInterval(ele.t);
221                 // 结束的位置要做什么,交给使用者决定
222                 // 传个功能进来,传函数
223                 cb && cb();
224             }
225         }, 30);
226     }
227     // 获取样式的兼容处理
228     function getStyle(ele, attr) {
229         if (ele.currentStyle) {
230             return ele.currentStyle[attr];
231         } else {
232             return getComputedStyle(ele, false)[attr];
233         }
234     }
235 </script>
236 </html>

 

 

欢迎各位宝宝留言!!!

上一篇:react源码解析9.diff算法


下一篇:栏中栏