/** * @desc 一个轮播插件 * @author Mxsyx (zsimline@163.com) * @version 1.0.0 */ class Lb { constructor(options) { this.lbBox = document.getElementById(options.id); this.lbItems = this.lbBox.querySelectorAll('.lb-item'); this.lbSigns = this.lbBox.querySelectorAll('.lb-sign li'); this.lbCtrlL = this.lbBox.querySelectorAll('.lb-ctrl')[0]; this.lbCtrlR = this.lbBox.querySelectorAll('.lb-ctrl')[1]; // 当前图片索引 this.curIndex = 0; // 轮播盒内图片数量 this.numItems = this.lbItems.length; // 是否可以滑动 this.status = true; // 轮播速度 this.speed = options.speed || 600; // 等待延时 this.delay = options.delay || 3000; // 轮播方向 this.direction = options.direction || 'left'; // 是否监听键盘事件 this.moniterKeyEvent = options.moniterKeyEvent || false; // 是否监听屏幕滑动事件 this.moniterTouchEvent = options.moniterTouchEvent || false; this.handleEvents(); this.setTransition(); } // 开始轮播 start() { const event = { srcElement: this.direction == 'left' ? this.lbCtrlR : this.lbCtrlL }; const clickCtrl = this.clickCtrl.bind(this); // 每隔一段时间模拟点击控件 this.interval = setInterval(clickCtrl, this.delay, event); } // 暂停轮播 pause() { clearInterval(this.interval); } /** * 设置轮播图片的过渡属性 * 在文件头内增加一个样式标签 * 标签内包含轮播图的过渡属性 */ setTransition() { const styleElement = document.createElement('style'); document.head.appendChild(styleElement); const styleRule = `.lb-item {transition: left ${this.speed}ms ease-in-out}` styleElement.sheet.insertRule(styleRule, 0); } // 处理点击控件事件 clickCtrl(event) { if (!this.status) return; this.status = false; if (event.srcElement == this.lbCtrlR) { var fromIndex = this.curIndex, toIndex = (this.curIndex + 1) % this.numItems, direction = 'left'; } else { var fromIndex = this.curIndex; toIndex = (this.curIndex + this.numItems - 1) % this.numItems, direction = 'right'; } this.slide(fromIndex, toIndex, direction); this.curIndex = toIndex; } // 处理点击标志事件 clickSign(event) { if (!this.status) return; this.status = false; const fromIndex = this.curIndex; const toIndex = parseInt(event.srcElement.getAttribute('slide-to')); const direction = fromIndex < toIndex ? 'left' : 'right'; this.slide(fromIndex, toIndex, direction); this.curIndex = toIndex; } // 处理滑动屏幕事件 touchScreen(event) { if (event.type == 'touchstart') { this.startX = event.touches[0].pageX; this.startY = event.touches[0].pageY; } else { // touchend this.endX = event.changedTouches[0].pageX; this.endY = event.changedTouches[0].pageY; // 计算滑动方向的角度 const dx = this.endX - this.startX const dy = this.startY - this.endY; const angle = Math.abs(Math.atan2(dy, dx) * 180 / Math.PI); // 滑动距离太短 if (Math.abs(dx) < 10 || Math.abs(dy) < 10) return ; if (angle >= 0 && angle <= 45) { // 向右侧滑动屏幕,模拟点击左控件 this.lbCtrlL.click(); } else if (angle >= 135 && angle <= 180) { // 向左侧滑动屏幕,模拟点击右控件 this.lbCtrlR.click(); } } } // 处理键盘按下事件 keyDown(event) { if (event && event.keyCode == 37) { this.lbCtrlL.click(); } else if (event && event.keyCode == 39) { this.lbCtrlR.click(); } } // 处理各类事件 handleEvents() { // 鼠标移动到轮播盒上时继续轮播 this.lbBox.addEventListener('mouseleave', this.start.bind(this)); // 鼠标从轮播盒上移开时暂停轮播 this.lbBox.addEventListener('mouseover', this.pause.bind(this)); // 点击左侧控件向右滑动图片 this.lbCtrlL.addEventListener('click', this.clickCtrl.bind(this)); // 点击右侧控件向左滑动图片 this.lbCtrlR.addEventListener('click', this.clickCtrl.bind(this)); // 点击轮播标志后滑动到对应的图片 for (let i = 0; i < this.lbSigns.length; i++) { this.lbSigns[i].setAttribute('slide-to', i); this.lbSigns[i].addEventListener('click', this.clickSign.bind(this)); } // 监听键盘事件 if (this.moniterKeyEvent) { document.addEventListener('keydown', this.keyDown.bind(this)); } // 监听屏幕滑动事件 if (this.moniterTouchEvent) { this.lbBox.addEventListener('touchstart', this.touchScreen.bind(this)); this.lbBox.addEventListener('touchend', this.touchScreen.bind(this)); } } /** * 滑动图片 * @param {number} fromIndex * @param {number} toIndex * @param {string} direction */ slide(fromIndex, toIndex, direction) { if (direction == 'left') { this.lbItems[toIndex].className = "lb-item next"; var fromClass = 'lb-item active left', toClass = 'lb-item next left'; } else { this.lbItems[toIndex].className = "lb-item prev"; var fromClass = 'lb-item active right', toClass = 'lb-item prev right'; } this.lbSigns[fromIndex].className = ""; this.lbSigns[toIndex].className = "active"; setTimeout((() => { this.lbItems[fromIndex].className = fromClass; this.lbItems[toIndex].className = toClass; }).bind(this), 50); setTimeout((() => { this.lbItems[fromIndex].className = 'lb-item'; this.lbItems[toIndex].className = 'lb-item active'; this.status = true; // 设置为可以滑动 }).bind(this), this.speed + 50); } }