You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

383 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
@Title: slider 滑块组件
@LicenseMIT
*/
layui.define('jquery', function(exports){
"use strict";
var $ = layui.jquery
//外部接口
,slider = {
config: {}
,index: layui.slider ? (layui.slider.index + 10000) : 0
//设置全局项
,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);
}
}
//操作当前实例
,thisSlider = function(){
var that = this
,options = that.config;
return {
setValue: function(value, index){ //设置值
options.value = value;
return that.slide('set', value, index || 0);
}
,config: options
}
}
//字符常量
,MOD_NAME = 'slider', DISABLED = 'layui-disabled', ELEM_VIEW = 'layui-slider', SLIDER_BAR = 'layui-slider-bar', SLIDER_WRAP = 'layui-slider-wrap', SLIDER_WRAP_BTN = 'layui-slider-wrap-btn', SLIDER_TIPS = 'layui-slider-tips', SLIDER_INPUT = 'layui-slider-input', SLIDER_INPUT_TXT = 'layui-slider-input-txt', SLIDER_INPUT_BTN = 'layui-slider-input-btn', ELEM_HOVER = 'layui-slider-hover'
//构造器
,Class = function(options){
var that = this;
that.index = ++slider.index;
that.config = $.extend({}, that.config, slider.config, options);
that.render();
};
//默认配置
Class.prototype.config = {
type: 'default' //滑块类型垂直vertical
,min: 0 //最小值
,max: 100 //最大值默认100
,value: 0 //初始值默认为0
,step: 1 //间隔值
,showstep: false //间隔点开启
,tips: true //文字提示,开启
,input: false //输入框,关闭
,range: false //范围选择,与输入框不能同时开启,默认关闭
,height: 200 //配合 type:"vertical" 使用默认200px
,disabled: false //滑块禁用,默认关闭
,theme: '#009688' //主题颜色
};
//滑块渲染
Class.prototype.render = function(){
var that = this
,options = that.config;
//间隔值不能小于 1
if(options.step < 1) options.step = 1;
//最大值不能小于最小值
if(options.max < options.min) options.max = options.min + options.step;
//判断是否开启双滑块
if(options.range){
options.value = typeof(options.value) == 'object' ? options.value : [options.min, options.value];
var minValue = Math.min(options.value[0], options.value[1])
,maxValue = Math.max(options.value[0], options.value[1]);
options.value[0] = minValue > options.min ? minValue : options.min;
options.value[1] = maxValue > options.min ? maxValue : options.min;
options.value[0] = options.value[0] > options.max ? options.max : options.value[0];
options.value[1] = options.value[1] > options.max ? options.max : options.value[1];
var scaleFir = Math.floor((options.value[0] - options.min) / (options.max - options.min) * 100)
,scaleSec = Math.floor((options.value[1] - options.min) / (options.max - options.min) * 100)
,scale = scaleSec - scaleFir + '%';
scaleFir = scaleFir + '%';
scaleSec = scaleSec + '%';
} else {
//如果初始值是一个数组,则获取数组的最小值
if(typeof options.value == 'object'){
options.value = Math.min.apply(null, options.value);
}
//初始值不能小于最小值且不能大于最大值
if(options.value < options.min) options.value = options.min;
if(options.value > options.max) options.value = options.max;
var scale = Math.floor((options.value - options.min) / (options.max - options.min) * 100) + '%';
};
//如果禁用,颜色为统一的灰色
var theme = options.disabled ? '#c2c2c2' : options.theme;
//滑块
var temp = '<div class="layui-slider '+ (options.type === 'vertical' ? 'layui-slider-vertical' : '') +'">'+ (options.tips ? '<div class="layui-slider-tips"></div>' : '') +
'<div class="layui-slider-bar" style="background:'+ theme +'; '+ (options.type === 'vertical' ? 'height' : 'width') +':'+ scale +';'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ (scaleFir || 0) +';"></div><div class="layui-slider-wrap" style="'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ (scaleFir || scale) +';">' +
'<div class="layui-slider-wrap-btn" style="border: 2px solid '+ theme +';"></div></div>'+ (options.range ? '<div class="layui-slider-wrap" style="'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ scaleSec +';"><div class="layui-slider-wrap-btn" style="border: 2px solid '+ theme +';"></div></div>' : '') +'</div>';
var othis = $(options.elem)
,hasRender = othis.next('.' + ELEM_VIEW);
//生成替代元素
hasRender[0] && hasRender.remove(); //如果已经渲染则Rerender
that.elemTemp = $(temp);
//把数据缓存到滑块上
if(options.range){
that.elemTemp.find('.' + SLIDER_WRAP).eq(0).data('value', options.value[0]);
that.elemTemp.find('.' + SLIDER_WRAP).eq(1).data('value', options.value[1]);
}else{
that.elemTemp.find('.' + SLIDER_WRAP).data('value', options.value);
};
//插入替代元素
othis.html(that.elemTemp);
//垂直滑块
if(options.type === 'vertical'){
that.elemTemp.height(options.height + 'px');
};
//显示间断点
if(options.showstep){
var number = (options.max - options.min) / options.step, item = '';
for(var i = 1; i < number + 1; i++) {
var step = i * 100 / number;
if(step < 100){
item += '<div class="layui-slider-step" style="'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ step +'%"></div>'
}
};
that.elemTemp.append(item);
};
//插入输入框
if(options.input && !options.range){
var elemInput = $('<div class="layui-slider-input layui-input"><div class="layui-slider-input-txt"><input type="text" class="layui-input"></div><div class="layui-slider-input-btn"><i class="layui-icon layui-icon-up"></i><i class="layui-icon layui-icon-down"></i></div></div>');
othis.css("position","relative");
othis.append(elemInput);
othis.find('.' + SLIDER_INPUT_TXT).children('input').val(options.value);
if(options.type === 'vertical'){
elemInput.css({
left: 0
,top: -48
});
} else {
that.elemTemp.css("margin-right", elemInput.outerWidth() + 15);
}
};
//给未禁止的滑块滑动事件
if(!options.disabled){
that.slide();
}else{
that.elemTemp.addClass(DISABLED);
that.elemTemp.find('.' + SLIDER_WRAP_BTN).addClass(DISABLED);
};
//划过滑块显示数值
that.elemTemp.find('.' + SLIDER_WRAP_BTN).on('mouseover', function(){
var sliderWidth = options.type === 'vertical' ? options.height : that.elemTemp[0].offsetWidth
,sliderWrap = that.elemTemp.find('.' + SLIDER_WRAP)
,tipsLeft = options.type === 'vertical' ? (sliderWidth - $(this).parent()[0].offsetTop - sliderWrap.height()) : $(this).parent()[0].offsetLeft
,left = tipsLeft / sliderWidth * 100
,value = $(this).parent().data('value')
,tipsTxt = options.setTips ? options.setTips(value) : value;
that.elemTemp.find('.' + SLIDER_TIPS).html(tipsTxt);
if(options.type === 'vertical'){
that.elemTemp.find('.' + SLIDER_TIPS).css({"bottom":left + '%', "margin-bottom":"20px", "display":"inline-block"});
}else{
that.elemTemp.find('.' + SLIDER_TIPS).css({"left":left + '%', "display":"inline-block"});
};
}).on('mouseout', function(){
that.elemTemp.find('.' + SLIDER_TIPS).css("display", "none");
});
};
//滑块滑动
Class.prototype.slide = function(setValue, value, i){
var that = this
,options = that.config
,sliderAct = that.elemTemp
,sliderWidth = function(){
return options.type === 'vertical' ? options.height : sliderAct[0].offsetWidth
}
,sliderWrap = sliderAct.find('.' + SLIDER_WRAP)
,sliderTxt = sliderAct.next('.' + SLIDER_INPUT)
,inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val()
,step = 100 / ((options.max - options.min) / Math.ceil(options.step))
,change = function(offsetValue, index){
if(Math.ceil(offsetValue) * step > 100){
offsetValue = Math.ceil(offsetValue) * step
}else{
offsetValue = Math.round(offsetValue) * step
};
offsetValue = offsetValue > 100 ? 100: offsetValue;
sliderWrap.eq(index).css((options.type === 'vertical' ?'bottom':'left'), offsetValue + '%');
var firLeft = valueTo(sliderWrap[0].offsetLeft)
,secLeft = options.range ? valueTo(sliderWrap[1].offsetLeft) : 0;
if(options.type === 'vertical'){
sliderAct.find('.' + SLIDER_TIPS).css({"bottom":offsetValue + '%', "margin-bottom":"20px"});
firLeft = valueTo(sliderWidth() - sliderWrap[0].offsetTop - sliderWrap.height());
secLeft = options.range ? valueTo(sliderWidth() - sliderWrap[1].offsetTop - sliderWrap.height()) : 0;
}else{
sliderAct.find('.' + SLIDER_TIPS).css("left",offsetValue + '%');
};
firLeft = firLeft > 100 ? 100: firLeft;
secLeft = secLeft > 100 ? 100: secLeft;
var minLeft = Math.min(firLeft, secLeft)
,wrapWidth = Math.abs(firLeft - secLeft);
if(options.type === 'vertical'){
sliderAct.find('.' + SLIDER_BAR).css({"height":wrapWidth + '%', "bottom":minLeft + '%'});
}else{
sliderAct.find('.' + SLIDER_BAR).css({"width":wrapWidth + '%', "left":minLeft + '%'});
};
var selfValue = options.min + Math.round((options.max - options.min) * offsetValue / 100);
inputValue = selfValue;
sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val(inputValue);
sliderWrap.eq(index).data('value', selfValue);
sliderAct.find('.' + SLIDER_TIPS).html(options.setTips ? options.setTips(selfValue) : selfValue);
//如果开启范围选择,则返回数组值
if(options.range){
var arrValue = [
sliderWrap.eq(0).data('value')
,sliderWrap.eq(1).data('value')
];
if(arrValue[0] > arrValue[1]) arrValue.reverse(); //如果前面的圆点超过了后面的圆点值,则调换顺序
}
//回调
options.change && options.change(options.range ? arrValue : selfValue);
}
,valueTo = function(value){
var oldLeft = value / sliderWidth() * 100 / step
,left = Math.round(oldLeft) * step;
if(value == sliderWidth()){
left = Math.ceil(oldLeft) * step;
};
return left;
}
//拖拽元素
,elemMove = $(['<div class="layui-auxiliar-moving" id="LAY-slider-moving"></div'].join(''))
,createMoveElem = function(move, up){
var upCall = function(){
up && up();
elemMove.remove();
};
$('#LAY-slider-moving')[0] || $('body').append(elemMove);
elemMove.on('mousemove', move);
elemMove.on('mouseup', upCall).on('mouseleave', upCall);
};
//动态赋值
if(setValue === 'set') return change(value, i);
//滑块滑动
sliderAct.find('.' + SLIDER_WRAP_BTN).each(function(index){
var othis = $(this);
othis.on('mousedown', function(e){
e = e || window.event;
var oldleft = othis.parent()[0].offsetLeft
,oldx = e.clientX;
if(options.type === 'vertical'){
oldleft = sliderWidth() - othis.parent()[0].offsetTop - sliderWrap.height()
oldx = e.clientY;
};
var move = function(e){
e = e || window.event;
var left = oldleft + (options.type === 'vertical' ? (oldx - e.clientY) : (e.clientX - oldx));
if(left < 0)left = 0;
if(left > sliderWidth())left = sliderWidth();
var reaLeft = left / sliderWidth() * 100 / step;
change(reaLeft, index);
othis.addClass(ELEM_HOVER);
sliderAct.find('.' + SLIDER_TIPS).show();
e.preventDefault();
};
var up = function(){
othis.removeClass(ELEM_HOVER);
sliderAct.find('.' + SLIDER_TIPS).hide();
};
createMoveElem(move, up)
});
});
//点击滑块
sliderAct.on('click', function(e){
var main = $('.' + SLIDER_WRAP_BTN);
if(!main.is(event.target) && main.has(event.target).length === 0 && main.length){
var left = options.type === 'vertical' ? (sliderWidth() - e.clientY + $(this).offset().top):(e.clientX - $(this).offset().left), index;
if(left < 0)left = 0;
if(left > sliderWidth())left = sliderWidth();
var reaLeft = left / sliderWidth() * 100 / step;
if(options.range){
if(options.type === 'vertical'){
index = Math.abs(left - parseInt($(sliderWrap[0]).css('bottom'))) > Math.abs(left - parseInt($(sliderWrap[1]).css('bottom'))) ? 1 : 0;
}else{
index = Math.abs(left - sliderWrap[0].offsetLeft) > Math.abs(left - sliderWrap[1].offsetLeft) ? 1 : 0;
}
}else{
index = 0;
};
change(reaLeft, index);
e.preventDefault();
}
});
//点击加减输入框
sliderTxt.children('.' + SLIDER_INPUT_BTN).children('i').each(function(index){
$(this).on('click', function(){
inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val();
if(index == 1){ //减
inputValue = inputValue - options.step < options.min
? options.min
: Number(inputValue) - options.step;
}else{
inputValue = Number(inputValue) + options.step > options.max
? options.max
: Number(inputValue) + options.step;
};
var inputScale = (inputValue - options.min) / (options.max - options.min) * 100 / step;
change(inputScale, 0);
});
});
//获取输入框值
var getInputValue = function(){
var realValue = this.value;
realValue = isNaN(realValue) ? 0 : realValue;
realValue = realValue < options.min ? options.min : realValue;
realValue = realValue > options.max ? options.max : realValue;
this.value = realValue;
var inputScale = (realValue - options.min) / (options.max - options.min) * 100 / step;
change(inputScale, 0);
};
sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').on('keydown', function(e){
if(e.keyCode === 13){
e.preventDefault();
getInputValue.call(this);
}
}).on('change', getInputValue);
};
//事件处理
Class.prototype.events = function(){
var that = this
,options = that.config;
};
//核心入口
slider.render = function(options){
var inst = new Class(options);
return thisSlider.call(inst);
};
exports(MOD_NAME, slider);
})