diff --git a/src/modules/slider.js b/src/modules/slider.js index a95ccbfe..97d55b53 100644 --- a/src/modules/slider.js +++ b/src/modules/slider.js @@ -2,83 +2,228 @@ * slider 滑块组件 */ -layui.define(['jquery', 'lay'], function(exports) { +layui.define(['component', 'jquery', 'lay'], function(exports) { 'use strict'; var $ = layui.$; var lay = layui.lay; - // 外部接口 - var slider = { - config: {}, - index: layui.slider ? (layui.slider.index + 10000) : 0, - - // 设置全局项 - set: function(options) { - var that = this; - that.config = $.extend({}, that.config, options); - return that; + var component = layui.component({ + name: 'slider', + config: { + type: 'default', //滑块类型,垂直:vertical + min: 0, //最小值 + max: 100, //最大值,默认100 + value: 0, //初始值,默认为0 + step: 1, //间隔值 + showstep: false, //间隔点开启 + tips: true, //文字提示,开启 + tipsAlways: false, //文字提示,始终开启 + input: false, //输入框,关闭 + range: false, //范围选择,与输入框不能同时开启,默认关闭 + height: 200, //配合 type:"vertical" 使用,默认200px + disabled: false, //滑块禁用,默认关闭 + theme: '#16baaa' //主题颜色 }, + CONST: { + 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', + }, + render: function (rerender) { + var that = this; + var options = that.config; - // 事件 - on: function(events, callback) { - return layui.onevent.call(this, MOD_NAME, events, callback); + //间隔值不能小于等于 0 + if (options.step <= 0) 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] = Math.max(minValue, options.min); + options.value[1] = Math.max(maxValue, options.min); + options.value[0] = Math.min(options.value[0], options.max); + options.value[1] = Math.min(options.value[1], options.max); + + var scaleFir = (options.value[0] - options.min) / (options.max - options.min) * 100; + var scaleSec = (options.value[1] - options.min) / (options.max - options.min) * 100; + var 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 = (options.value - options.min) / (options.max - options.min) * 100 + '%'; + } + + + //如果禁用,颜色为统一的灰色 + var theme = options.disabled ? '#c2c2c2' : options.theme; + + //滑块 + var temp = '
'; + + var othis = $(options.elem); + var hasRender = othis.next('.' + CONST.ELEM_VIEW); + //生成替代元素 + hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender + that.elemTemp = $(temp); + + //把数据缓存到滑块上 + if (options.range) { + that.elemTemp.find('.' + CONST.SLIDER_WRAP).eq(0).data('value', options.value[0]); + that.elemTemp.find('.' + CONST.SLIDER_WRAP).eq(1).data('value', options.value[1]); + } else { + that.elemTemp.find('.' + CONST.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 += '' + } + } + that.elemTemp.append(item); + } + + //插入输入框 + if (options.input && !options.range) { + var elemInput = $(' '); + othis.css("position", "relative"); + othis.append(elemInput); + othis.find('.' + CONST.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(CONST.CLASS_DISABLED); + that.elemTemp.find('.' + CONST.SLIDER_WRAP_BTN).addClass(CONST.CLASS_DISABLED); + } + + /** + * @description 设置提示文本内容 + * @param {Element} sliderWrapBtnElem 提示文本节点元素 + */ + function setSliderTipsTxt(sliderWrapBtnElem) { + var value = sliderWrapBtnElem.parent().data('value'); + var tipsTxt = options.setTips ? options.setTips(value) : value; + that.elemTemp.find('.' + CONST.SLIDER_TIPS).html(tipsTxt); + } + + /** + * @description 计算提示文本元素的 position left + * @param {Element} sliderWrapBtnElem 提示文本节点元素 + */ + function calcSliderTipsLeft(sliderWrapBtnElem) { + var sliderWidth = options.type === 'vertical' ? options.height : that.elemTemp[0].offsetWidth; + var sliderWrap = that.elemTemp.find('.' + CONST.SLIDER_WRAP); + var tipsLeft = options.type === 'vertical' ? (sliderWidth - sliderWrapBtnElem.parent()[0].offsetTop - sliderWrap.height()) : sliderWrapBtnElem.parent()[0].offsetLeft; + var left = tipsLeft / sliderWidth * 100; + return left + } + + /** + * @description 设置提示文本元素的 position left + * @param {number} left 要设置的 left 的大小 + */ + function setSliderTipsLeft(left) { + if (options.type === 'vertical') { + that.elemTemp.find('.' + CONST.SLIDER_TIPS).css({ + "bottom": left + '%', + "margin-bottom": "20px", + "display": "inline-block" + }); + } else { + that.elemTemp.find('.' + CONST.SLIDER_TIPS).css({ + "left": left + '%', + "display": "inline-block" + }); + } + } + + //判断是否要始终显示提示文本 + if (options.tips) { + if (options.tipsAlways) { + var sliderWrapBtnElem = that.elemTemp.find('.' + CONST.SLIDER_WRAP_BTN); + setSliderTipsTxt(sliderWrapBtnElem) + var left = calcSliderTipsLeft(sliderWrapBtnElem); + setSliderTipsLeft(left) + } else { + //划过滑块显示数值 + var timer; + that.elemTemp.find('.' + CONST.SLIDER_WRAP_BTN).on('mouseover', function () { + setSliderTipsTxt($(this)) + var left = calcSliderTipsLeft($(this)); + clearTimeout(timer); + timer = setTimeout(function () { + setSliderTipsLeft(left) + }, 300); + }).on('mouseout', function () { + clearTimeout(timer); + if (!options.tipsAlways) { + that.elemTemp.find('.' + CONST.SLIDER_TIPS).css("display", "none"); + } + }); + } + } + }, + extendsInstance: function(){ + var that = this; + var options = that.config; + return { + setValue: function (value, index) { + value = value > options.max ? options.max : value; + value = value < options.min ? options.min : value; + options.value = value; + return that.slide('set', value, index || 0); + } + }; } - }; + }); - // 操作当前实例 - var thisSlider = function(){ - var that = this; - var options = that.config; - - return { - setValue: function(value, index){ // 设置值 - value = value > options.max ? options.max : value; - value = value < options.min ? options.min : value; - options.value = value; - return that.slide('set', value, index || 0); - }, - config: options - } - }; - - // 字符常量 - var MOD_NAME = 'slider'; - var DISABLED = 'layui-disabled'; - var ELEM_VIEW = 'layui-slider'; - var SLIDER_BAR = 'layui-slider-bar'; - var SLIDER_WRAP = 'layui-slider-wrap'; - var SLIDER_WRAP_BTN = 'layui-slider-wrap-btn'; - var SLIDER_TIPS = 'layui-slider-tips'; - var SLIDER_INPUT = 'layui-slider-input'; - var SLIDER_INPUT_TXT = 'layui-slider-input-txt'; - var SLIDER_INPUT_BTN = 'layui-slider-input-btn'; - var ELEM_HOVER = 'layui-slider-hover'; - - // 构造器 - var 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, //文字提示,开启 - tipsAlways: false, //文字提示,始终开启 - input: false, //输入框,关闭 - range: false, //范围选择,与输入框不能同时开启,默认关闭 - height: 200, //配合 type:"vertical" 使用,默认200px - disabled: false, //滑块禁用,默认关闭 - theme: '#16baaa' //主题颜色 - }; + var CONST = component.CONST; + var Class = component.Class; // 数值精度 Class.prototype.precision = function(){ @@ -91,196 +236,6 @@ layui.define(['jquery', 'lay'], function(exports) { return Math.max.apply(null, precisions); } - //滑块渲染 - Class.prototype.render = function(){ - var that = this; - var options = that.config; - - // 若 elem 非唯一,则拆分为多个实例 - var elem = $(options.elem); - if(elem.length > 1){ - layui.each(elem, function(){ - slider.render($.extend({}, options, { - elem: this - })); - }); - return that; - } - - // 合并 lay-options 属性上的配置信息 - $.extend(options, lay.options(elem[0])); - - //间隔值不能小于等于 0 - if(options.step <= 0) 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] = Math.max(minValue,options.min); - options.value[1] = Math.max(maxValue,options.min); - options.value[0] = Math.min(options.value[0],options.max); - options.value[1] = Math.min(options.value[1],options.max); - - var scaleFir = (options.value[0] - options.min) / (options.max - options.min) * 100; - var scaleSec = (options.value[1] - options.min) / (options.max - options.min) * 100; - var 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 = (options.value - options.min) / (options.max - options.min) * 100 + '%'; - } - - - //如果禁用,颜色为统一的灰色 - var theme = options.disabled ? '#c2c2c2' : options.theme; - - //滑块 - var temp = ' '; - - var othis = $(options.elem); - var 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 += '' - } - } - that.elemTemp.append(item); - } - - //插入输入框 - if(options.input && !options.range){ - var elemInput = $(' '); - 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); - } - - /** - * @description 设置提示文本内容 - * @param {Element} sliderWrapBtnElem 提示文本节点元素 - */ - function setSliderTipsTxt(sliderWrapBtnElem) { - var value = sliderWrapBtnElem.parent().data('value'); - var tipsTxt = options.setTips ? options.setTips(value) : value; - that.elemTemp.find('.' + SLIDER_TIPS).html(tipsTxt); - } - - /** - * @description 计算提示文本元素的 position left - * @param {Element} sliderWrapBtnElem 提示文本节点元素 - */ - function calcSliderTipsLeft(sliderWrapBtnElem){ - var sliderWidth = options.type === 'vertical' ? options.height : that.elemTemp[0].offsetWidth; - var sliderWrap = that.elemTemp.find('.' + SLIDER_WRAP); - var tipsLeft = options.type === 'vertical' ? (sliderWidth - sliderWrapBtnElem.parent()[0].offsetTop - sliderWrap.height()) : sliderWrapBtnElem.parent()[0].offsetLeft; - var left = tipsLeft / sliderWidth * 100; - return left - } - - /** - * @description 设置提示文本元素的 position left - * @param {number} left 要设置的 left 的大小 - */ - function setSliderTipsLeft(left) { - 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" - }); - } - } - - //判断是否要始终显示提示文本 - if(options.tips){ - if(options.tipsAlways){ - var sliderWrapBtnElem = that.elemTemp.find('.' + SLIDER_WRAP_BTN); - setSliderTipsTxt(sliderWrapBtnElem) - var left = calcSliderTipsLeft(sliderWrapBtnElem); - setSliderTipsLeft(left) - }else{ - //划过滑块显示数值 - var timer; - that.elemTemp.find('.' + SLIDER_WRAP_BTN).on('mouseover', function(){ - setSliderTipsTxt($(this)) - var left = calcSliderTipsLeft($(this)); - clearTimeout(timer); - timer = setTimeout(function(){ - setSliderTipsLeft(left) - }, 300); - }).on('mouseout', function(){ - clearTimeout(timer); - if(!options.tipsAlways){ - that.elemTemp.find('.' + SLIDER_TIPS).css("display", "none"); - } - }); - } - } - }; - //滑块滑动 Class.prototype.slide = function(setValue, value, i){ var that = this; @@ -289,9 +244,9 @@ layui.define(['jquery', 'lay'], function(exports) { var sliderWidth = function(){ return options.type === 'vertical' ? options.height : sliderAct[0].offsetWidth }; - var sliderWrap = sliderAct.find('.' + SLIDER_WRAP); - var sliderTxt = sliderAct.next('.' + SLIDER_INPUT); - var inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val(); + var sliderWrap = sliderAct.find('.' + CONST.SLIDER_WRAP); + var sliderTxt = sliderAct.next('.' + CONST.SLIDER_INPUT); + var inputValue = sliderTxt.children('.' + CONST.SLIDER_INPUT_TXT).children('input').val(); var step = 100 / ((options.max - options.min) / options.step); var precision = that.precision(); var change = function(offsetValue, index, from){ @@ -306,27 +261,27 @@ layui.define(['jquery', 'lay'], function(exports) { var firLeft = valueTo(sliderWrap[0].offsetLeft); var secLeft = options.range ? valueTo(sliderWrap[1].offsetLeft) : 0; if(options.type === 'vertical'){ - sliderAct.find('.' + SLIDER_TIPS).css({"bottom":offsetValue + '%', "margin-bottom":"20px"}); + sliderAct.find('.' + CONST.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 + '%'); + sliderAct.find('.' + CONST.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 + '%'}); + sliderAct.find('.' + CONST.SLIDER_BAR).css({"height":wrapWidth + '%', "bottom":minLeft + '%'}); }else{ - sliderAct.find('.' + SLIDER_BAR).css({"width":wrapWidth + '%', "left":minLeft + '%'}); + sliderAct.find('.' + CONST.SLIDER_BAR).css({"width":wrapWidth + '%', "left":minLeft + '%'}); } var selfValue = options.min + (options.max - options.min) * offsetValue / 100; selfValue = Number(parseFloat(selfValue).toFixed(precision)); inputValue = selfValue; - sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val(inputValue); + sliderTxt.children('.' + CONST.SLIDER_INPUT_TXT).children('input').val(inputValue); sliderWrap.eq(index).data('value', selfValue); - sliderAct.find('.' + SLIDER_TIPS).html(options.setTips ? options.setTips(selfValue) : selfValue); + sliderAct.find('.' + CONST.SLIDER_TIPS).html(options.setTips ? options.setTips(selfValue) : selfValue); //如果开启范围选择,则返回数组值 if(options.range){ @@ -384,7 +339,7 @@ layui.define(['jquery', 'lay'], function(exports) { } //滑块滑动 - sliderAct.find('.' + SLIDER_WRAP_BTN).each(function(index){ + sliderAct.find('.' + CONST.SLIDER_WRAP_BTN).each(function(index){ var othis = $(this); othis.on('mousedown touchstart', function(e){ e = e || window.event; @@ -411,16 +366,16 @@ layui.define(['jquery', 'lay'], function(exports) { if(left > sliderWidth())left = sliderWidth(); var reaLeft = left / sliderWidth() * 100 / step; change(reaLeft, index); - othis.addClass(ELEM_HOVER); - sliderAct.find('.' + SLIDER_TIPS).show(); + othis.addClass(CONST.ELEM_HOVER); + sliderAct.find('.' + CONST.SLIDER_TIPS).show(); e.preventDefault(); }; var up = function(delay){ - othis.removeClass(ELEM_HOVER); + othis.removeClass(CONST.ELEM_HOVER); if(!options.tipsAlways){ setTimeout(function(){ - sliderAct.find('.' + SLIDER_TIPS).hide(); + sliderAct.find('.' + CONST.SLIDER_TIPS).hide(); }, delay); } }; @@ -431,7 +386,7 @@ layui.define(['jquery', 'lay'], function(exports) { // 点击滑块 sliderAct.on('click', function(e){ - var main = $('.' + SLIDER_WRAP_BTN); + var main = $('.' + CONST.SLIDER_WRAP_BTN); var othis = $(this); if(!main.is(event.target) && main.has(event.target).length === 0 && main.length){ var index; @@ -457,9 +412,9 @@ layui.define(['jquery', 'lay'], function(exports) { }); //点击加减输入框 - sliderTxt.children('.' + SLIDER_INPUT_BTN).children('i').each(function(index){ + sliderTxt.children('.' + CONST.SLIDER_INPUT_BTN).children('i').each(function(index){ $(this).on('click', function(){ - inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val(); + inputValue = sliderTxt.children('.' + CONST.SLIDER_INPUT_TXT).children('input').val(); if(index == 1){ //减 inputValue = inputValue - options.step < options.min ? options.min @@ -484,7 +439,7 @@ layui.define(['jquery', 'lay'], function(exports) { var inputScale = (realValue - options.min) / (options.max - options.min) * 100 / step; change(inputScale, 0, 'done'); }; - sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').on('keydown', function(e){ + sliderTxt.children('.' + CONST.SLIDER_INPUT_TXT).children('input').on('keydown', function(e){ if(e.keyCode === 13){ e.preventDefault(); getInputValue.call(this); @@ -492,17 +447,5 @@ layui.define(['jquery', 'lay'], function(exports) { }).on('change', getInputValue); }; - //事件处理 - Class.prototype.events = function(){ - var that = this; - var options = that.config; - }; - - //核心入口 - slider.render = function(options){ - var inst = new Class(options); - return thisSlider.call(inst); - }; - - exports(MOD_NAME, slider); + exports(CONST.MOD_NAME, component); })