/** * carousel 轮播模块 * MIT Licensed */ layui.define(['jquery', 'lay'], function(exports){ "use strict"; var $ = layui.$; var lay = layui.lay; var hint = layui.hint(); var device = layui.device(); // 外部接口 var carousel = { config: {}, // 全局配置项 // 设置全局项 set: function(options){ var that = this; that.config = $.extend({}, that.config, options); return that; }, // 事件 on: function(events, callback){ return layui.onevent.call(this, MOD_NAME, events, callback); } }; // 字符常量 var MOD_NAME = 'carousel'; var ELEM = '.layui-carousel'; var THIS = 'layui-this'; var SHOW = 'layui-show'; var HIDE = 'layui-hide'; var DISABLED = 'layui-disabled' var ELEM_ITEM = '>*[carousel-item]>*'; var ELEM_LEFT = 'layui-carousel-left'; var ELEM_RIGHT = 'layui-carousel-right'; var ELEM_PREV = 'layui-carousel-prev'; var ELEM_NEXT = 'layui-carousel-next'; var ELEM_ARROW = 'layui-carousel-arrow'; var ELEM_IND = 'layui-carousel-ind'; // 构造器 var Class = function(options){ var that = this; that.config = $.extend({}, that.config, carousel.config, options); that.render(); }; // 默认配置 Class.prototype.config = { width: '600px', height: '280px', full: false, // 是否全屏 arrow: 'hover', // 切换箭头默认显示状态:hover/always/none indicator: 'inside', // 指示器位置:inside/outside/none autoplay: true, // 是否自动切换 interval: 3000, // 自动切换的时间间隔,不能低于800ms anim: '', // 动画类型:default/updown/fade trigger: 'click', // 指示器的触发方式:click/hover index: 0 // 初始开始的索引 }; // 轮播渲染 Class.prototype.render = function(){ var that = this; var options = that.config; // 若 elem 非唯一,则拆分为多个实例 var elem = $(options.elem); if(elem.length > 1){ layui.each(elem, function(){ carousel.render($.extend({}, options, { elem: this })); }); return that; } // 合并 lay-options 属性上的配置信息 $.extend(options, lay.options(elem[0])); options.elem = $(options.elem); if(!options.elem[0]) return; that.elemItem = options.elem.find(ELEM_ITEM); if(options.index < 0) options.index = 0; if(options.index >= that.elemItem.length) options.index = that.elemItem.length - 1; if(options.interval < 800) options.interval = 800; // 是否全屏模式 if(options.full){ options.elem.css({ position: 'fixed', width: '100%', height: '100%', zIndex: 9999 }); } else { options.elem.css({ width: options.width, height: options.height }); } options.elem.attr('lay-anim', options.anim); // 初始焦点状态 that.elemItem.eq(options.index).addClass(THIS); // 指示器、箭头等动作 that.indicator(); that.arrow(); that.autoplay(); if (that.elemItem.length > 1) { that.events(); } }; // 重置轮播 Class.prototype.reload = function(options){ var that = this; clearInterval(that.timer); that.config = $.extend({}, that.config, options); that.render(); }; // 获取上一个等待条目的索引 Class.prototype.prevIndex = function(){ var that = this; var options = that.config; var prevIndex = options.index - 1; if(prevIndex < 0){ prevIndex = that.elemItem.length - 1; } return prevIndex; }; // 获取下一个等待条目的索引 Class.prototype.nextIndex = function(){ var that = this; var options = that.config; var nextIndex = options.index + 1; if(nextIndex >= that.elemItem.length){ nextIndex = 0; } return nextIndex; }; // 索引递增 Class.prototype.addIndex = function(num){ var that = this; var options = that.config; num = num || 1; options.index = options.index + num; // index 不能超过轮播总数量 if(options.index >= that.elemItem.length){ options.index = 0; } }; // 索引递减 Class.prototype.subIndex = function(num){ var that = this; var options = that.config; num = num || 1; options.index = options.index - num; // index 不能超过轮播总数量 if(options.index < 0){ options.index = that.elemItem.length - 1; } }; // 自动轮播 Class.prototype.autoplay = function(){ var that = this; var options = that.config; var itemsCount = that.elemItem.length; if(!options.autoplay) return; clearInterval(that.timer); if (itemsCount > 1) { that.timer = setInterval(function(){ that.slide(); }, options.interval); } }; // 箭头 Class.prototype.arrow = function(){ var that = this; var options = that.config; var itemsCount = that.elemItem.length; // 模板 var tplArrow = $([ '', '' ].join('')); // 预设基础属性 options.elem.attr('lay-arrow', options.arrow); // 避免重复插入 if(options.elem.find('.'+ELEM_ARROW)[0]){ options.elem.find('.'+ELEM_ARROW).remove(); } itemsCount > 1 ? options.elem.append(tplArrow) : tplArrow.remove(); // 事件 tplArrow.on('click', function(){ var othis = $(this); var type = othis.attr('lay-type') that.slide(type); }); }; // 跳转到特定下标 Class.prototype.goto = function(index){ var that = this; var options = that.config; if(index > options.index){ that.slide('add', index - options.index); } else if(index < options.index){ that.slide('sub', options.index - index); } } // 指示器 Class.prototype.indicator = function(){ var that = this; var options = that.config; var itemsCount = that.elemItem.length; // 模板 var tplInd = that.elemInd = $(['
'].join('')); // 预设基础属性 options.elem.attr('lay-indicator', options.indicator); // 避免重复插入 if(options.elem.find('.'+ELEM_IND)[0]){ options.elem.find('.'+ELEM_IND).remove(); } itemsCount > 1 ? options.elem.append(tplInd) : tplInd.remove(); if(options.anim === 'updown'){ tplInd.css('margin-top', -(tplInd.height()/2)); } // 事件 tplInd.find('li').on(options.trigger === 'hover' ? 'mouseover' : options.trigger, function(){ that.goto($(this).index()); }); }; // 滑动切换 Class.prototype.slide = function(type, num){ var that = this; var elemItem = that.elemItem; var itemsCount = elemItem.length; var options = that.config; var thisIndex = options.index; var filter = options.elem.attr('lay-filter'); if (that.haveSlide || itemsCount <= 1) return; // 滑动方向 if(type === 'sub'){ that.subIndex(num); elemItem.eq(options.index).addClass(ELEM_PREV); setTimeout(function(){ elemItem.eq(thisIndex).addClass(ELEM_RIGHT); elemItem.eq(options.index).addClass(ELEM_RIGHT); }, 50); } else { // 默认递增滑 that.addIndex(num); elemItem.eq(options.index).addClass(ELEM_NEXT); setTimeout(function(){ elemItem.eq(thisIndex).addClass(ELEM_LEFT); elemItem.eq(options.index).addClass(ELEM_LEFT); }, 50); } // 移除过渡类 setTimeout(function(){ elemItem.removeClass(THIS + ' ' + ELEM_PREV + ' ' + ELEM_NEXT + ' ' + ELEM_LEFT + ' ' + ELEM_RIGHT); elemItem.eq(options.index).addClass(THIS); that.haveSlide = false; // 解锁 }, 350); // 指示器焦点 that.elemInd.find('li').eq(options.index).addClass(THIS) .siblings().removeClass(THIS); that.haveSlide = true; // 回调返回的参数 var params = { index: options.index, prevIndex: thisIndex, item: elemItem.eq(options.index) }; typeof options.change === 'function' && options.change(params); layui.event.call(this, MOD_NAME, 'change('+ filter +')', params); }; // 事件处理 Class.prototype.events = function(){ var that = this; var options = that.config; if(options.elem.data('haveEvents')) return; // 移入移出容器 options.elem.on('mouseenter touchstart', function(){ if (that.config.autoplay === 'always') return; clearInterval(that.timer); }).on('mouseleave touchend', function(){ if (that.config.autoplay === 'always') return; that.autoplay(); }); var touchEl = options.elem; var isVertical = options.anim === 'updown'; lay.touchSwipe(touchEl, { onTouchEnd: function(e, state){ var duration = Date.now() - state.timeStart; var distance = isVertical ? state.distanceY : state.distanceX; var speed = distance / duration; var shouldSwipe = Math.abs(speed) > 0.25 || Math.abs(distance) > touchEl[isVertical ? 'height' : 'width']() / 3; if(shouldSwipe){ that.slide(distance > 0 ? '' : 'sub'); } } }) options.elem.data('haveEvents', true); }; // 核心入口 carousel.render = function(options){ return new Class(options); }; exports(MOD_NAME, carousel); });