mirror of https://github.com/layui/layui
354 lines
8.9 KiB
JavaScript
354 lines
8.9 KiB
JavaScript
/**
|
||
* 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);
|
||
|
||
// 指示器等动作
|
||
if(that.elemItem.length <= 1) return;
|
||
|
||
that.indicator();
|
||
that.arrow();
|
||
that.autoplay();
|
||
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;
|
||
|
||
if(!options.autoplay) return;
|
||
clearInterval(that.timer);
|
||
|
||
that.timer = setInterval(function(){
|
||
that.slide();
|
||
}, options.interval);
|
||
};
|
||
|
||
// 箭头
|
||
Class.prototype.arrow = function(){
|
||
var that = this;
|
||
var options = that.config;
|
||
|
||
// 模板
|
||
var tplArrow = $([
|
||
'<button class="layui-icon '+ ELEM_ARROW +'" lay-type="sub">'+ (options.anim === 'updown' ? '' : '') +'</button>',
|
||
'<button class="layui-icon '+ ELEM_ARROW +'" lay-type="add">'+ (options.anim === 'updown' ? '' : '') +'</button>'
|
||
].join(''));
|
||
|
||
// 预设基础属性
|
||
options.elem.attr('lay-arrow', options.arrow);
|
||
|
||
// 避免重复插入
|
||
if(options.elem.find('.'+ELEM_ARROW)[0]){
|
||
options.elem.find('.'+ELEM_ARROW).remove();
|
||
}
|
||
options.elem.append(tplArrow);
|
||
|
||
// 事件
|
||
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 tplInd = that.elemInd = $(['<div class="'+ ELEM_IND +'"><ul>',
|
||
function(){
|
||
var li = [];
|
||
layui.each(that.elemItem, function(index){
|
||
li.push('<li'+ (options.index === index ? ' class="layui-this"' : '') +'></li>');
|
||
});
|
||
return li.join('');
|
||
}(),
|
||
'</ul></div>'].join(''));
|
||
|
||
// 预设基础属性
|
||
options.elem.attr('lay-indicator', options.indicator);
|
||
|
||
// 避免重复插入
|
||
if(options.elem.find('.'+ELEM_IND)[0]){
|
||
options.elem.find('.'+ELEM_IND).remove();
|
||
}
|
||
options.elem.append(tplInd);
|
||
|
||
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 options = that.config;
|
||
var thisIndex = options.index;
|
||
var filter = options.elem.attr('lay-filter');
|
||
|
||
if(that.haveSlide) 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', function(){
|
||
if (that.config.autoplay === 'always') return;
|
||
clearInterval(that.timer);
|
||
}).on('mouseleave', function(){
|
||
if (that.config.autoplay === 'always') return;
|
||
that.autoplay();
|
||
});
|
||
|
||
options.elem.data('haveEvents', true);
|
||
};
|
||
|
||
// 核心入口
|
||
carousel.render = function(options){
|
||
return new Class(options);
|
||
};
|
||
|
||
exports(MOD_NAME, carousel);
|
||
});
|
||
|
||
|