/** * Layui 数字输入组件 * * @author iTanken * @since 2019-03-29 * @version 2020-01-19:数字键盘纵向定位自适应 * @version 2020-04-02:添加功能按钮悬浮提示开关参数;添加悬浮提示内部键盘按钮样式;修复 number 类型输入框小数输入问题 */ layui.define(['jquery'], function(exports) { var $ = layui.$, baseClassName = 'layui-input-number', keyClassName = 'layui-keyboard-number', style = [''].join(''); $('head link:last')[0] && $('head link:last').after(style) || $('head').append(style); var numberInput = { /** 默认配置选项 */ options: { // 123:123键置顶, 789:789键置顶 topBtns: 123, // 右侧功能按钮 rightBtns: true, // 功能按钮提示 showTips: true, // 监听键盘事件 listening: true, // 批量配置默认小数精确度,-1 不处理精确度 defaultPrec: -1, // 初始化回调,无参 initEnd: $.noop, // 触发显示回调,参数为当前输入框和数字键盘的 jQuery 对象 showEnd: $.noop, // 隐藏键盘回调,参数为当前输入框的 jQuery 对象 hideEnd: $.noop, // z-index zIndex: 19999999 }, /** 初始化 */ init: function(custom) { var _this = this; _this.options = $.extend(_this.options, custom); $('.' + baseClassName).attr({ "readonly": "readonly" }).on('focus', function(e) { _this.showKeyboard(_this, $(this)); }); typeof _this.options.initEnd === 'function' && _this.options.initEnd(); }, /** 获取按键悬浮提示 */ getTips: function(tip) { return this.options.showTips ? (' lay-tips="' + tip + '"') : ''; }, /** 显示数字键盘 */ showKeyboard: function(_this, $input) { // 2020-04-02:修复小数输入问题,将 number 类型输入框一律设置为 text $input.prop('type') === 'number' && $input.attr('type', 'text'); var $keyBoard = $input.next('.' + keyClassName); if (!$keyBoard[0]) { // 不存在,添加元素 var sizeXS = _this.options.rightBtns ? 'xs3' : 'xs4', sizeZero = _this.options.rightBtns ? 'xs6' : 'xs4', // 按钮 123 btn123 = [ '
', '
', '
1
', '
', '
', '
', '
', '
2
', '
', '
', '
', '
', '
3
', '
', '
' ].join(''), // 按钮 789 btn789 = [ '
', '
', '
7
', '
', '
', '
', '
', '
8
', '
', '
', '
', '
', '
9
', '
', '
' ].join(''), /* 退格键 */ backspace = [ '
', '
', '
', 'Backspace'), '>', '
', '
', '
' ].join(''), /* 增加键 */ add = [ '
', '
', '
', '↑'), '>', '
', '
', '
' ].join(''), /* 减小键 */ reduce = [ '
', '
', '
', '↓'), '>', '
', '
', '
' ].join(''), /* 清空键 */ reset = [ '
', '
', '
', 'Delete'), '>', '
', '
', '
' ].join(''); $input.after(['
', '
', _this.options.topBtns == 789 ? btn789 : btn123, _this.options.rightBtns ? backspace : '', '
', '
', '
4
', '
', '
', '
', '
', '
5
', '
', '
', '
', '
', '
6
', '
', '
', _this.options.rightBtns ? add : '', _this.options.topBtns == 789 ? btn123 : btn789, _this.options.rightBtns ? reduce : '', _this.options.rightBtns ? '' : backspace, '
', '
', '
0
', '
', '
', '
', '
', '
.
', '
', '
', _this.options.rightBtns ? reset : '', '
', '
'].join('')); $keyBoard = $input.next('.' + keyClassName); $keyBoard.on('touchstart click', '.layui-key-btn', function(e) { _this.setValue(_this, $input, $(this)); layui.stope(e); return false; }); $keyBoard.on('blur', function(e) { _this.setValueRange(_this, $input, _this.toFixedPrec(_this, $input)); $keyBoard.remove(); // $keyBoard.hide(); typeof _this.options.hideEnd === 'function' && _this.options.hideEnd($input); }); _this.options.listening && _this.initKeyListening(_this, $input, $keyBoard); } _this.display(_this, $input, $keyBoard); }, /** 设置数字键盘样式并显示 */ display: function(_this, $input, $keyBoard) { var showTop = $input[0].offsetTop + $input[0].offsetHeight + 4, boardHeight = $keyBoard.height(), $win = $(window), topOffset = $keyBoard.offset().top + $keyBoard.outerHeight() + 4 - $win.scrollTop(); // 数字键盘纵向定位自适应 if (topOffset + boardHeight > $win.height() && topOffset >= boardHeight) { showTop = $input[0].offsetTop - boardHeight - 5; } $keyBoard.css({ 'top': showTop + 'px', 'left': $input[0].offsetLeft + 'px', 'z-index': _this.options.zIndex }); $keyBoard.show(200, function() { typeof _this.options.showEnd === 'function' && _this.options.showEnd($input, $keyBoard); }).focus(); }, /** 初始化键盘监听事件 */ initKeyListening: function(_this, $input, $keyBoard) { var $key, code; $keyBoard.on('keydown', function(e) { code = e.keyCode; var inputNumber = parseInt($input.val(), 10) || 0; if (code === 107 || e.shiftKey && code === 187) { // 加号切换正数 inputNumber < 0 && _this.setValueRange(_this, $input, Math.abs(inputNumber)); } else if (code === 109 || e.shiftKey && code === 189) { // 减号切换负数 inputNumber > 0 && _this.setValueRange(_this, $input, '-' + inputNumber); } else { // 监听数字键盘,退格键(Backspace)/重置键(Delete) $key = $keyBoard.find('.layui-key-btn[data-keycode~=' + code + ']'); if ($key[0]) { $key.trigger('click').css("background-color", "#f2f2f2"); $keyBoard.off('keyup').on('keyup', function(e) { $('.layui-key-btn[data-keycode]').css("background-color", "#ffffff"); }); } if (code > 36 && code < 41) { // 上下左右键,防止触发混动条滑动事件 return false; } } return true; }); }, /** 处理精确度 */ toFixedPrec: function(_this, $input, val1, val2) { var m, s, rs, prec = $.trim($input.data('prec')); // 2020-04-02:修复获取小数精确度配置值问题 prec = parseInt(prec === '' || isNaN(prec) ? _this.options.defaultPrec : prec, 10); val1 = val1 === undefined ? $input.val() : val1; val1 = val1 == '' ? ($input.attr('min') || 0) : val1; rs = val1.toString().split('.')[1]; if (prec < 0) { prec = rs && rs.length || prec; } val2 = val2 || 0; rs = val2.toString().split('.')[1]; prec = Math.max(prec, rs ? rs.length : 0); m = Math.pow(10, prec); s = ((val1 * m + val2 * m).toFixed(0) / m).toString(); rs = s.indexOf('.'); if (rs < 0 && prec > 0) { rs = s.length; s += '.'; } while (s.length <= rs + prec) { s += '0'; } return s; }, /** 设置值范围 */ setValueRange: function(_this, $input, value) { var minVal = $input.attr('min') || Math.pow(-2, 63), maxVal = $input.attr('max') || Math.pow(2, 63) - 1; minVal = typeof minVal === 'string' && minVal.indexOf('.') > -1 ? parseFloat(minVal) : parseInt(minVal, 10); maxVal = typeof maxVal === 'string' && maxVal.indexOf('.') > -1 ? parseFloat(maxVal) : parseInt(maxVal, 10); if (value < minVal) { value = _this.toFixedPrec(_this, $input, minVal); _this.tips($input, '最小值为 ' + minVal + '!'); } if (value > maxVal) { value = _this.toFixedPrec(_this, $input, maxVal); _this.tips($input, '最大值为 ' + maxVal + '!'); } value = value < minVal ? minVal : (value > maxVal ? maxVal : value); $input.val(value); }, /** 设置输入框值 */ setValue: function(_this, $input, $key) { var inputVal = $.trim($input.val()), keyVal = $.trim($key.text()), changeVal, prec = $.trim($input.data('prec')), isDecimal = inputVal.indexOf('.') > -1; // 2020-04-02:修复获取小数精确度配置值问题 prec = parseInt(prec === '' || isNaN(prec) ? _this.options.defaultPrec : prec, 10); if ($.inArray(keyVal, ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.']) > -1) { if (keyVal === '.') { if (inputVal === '' || isDecimal) { return; } if (prec === 0) { _this.tips($input, '当前字段不允许输入小数!'); return; } } if (keyVal === '0' && inputVal.indexOf('0') === 0 && !isDecimal) { return; } if (inputVal.indexOf('.') > -1 && inputVal.split('.')[1].length >= prec && prec > 0) { _this.tips($input, '精确度为保留小数点后 ' + prec + ' 位!'); return; } changeVal = inputVal = (keyVal !== '.' && inputVal === '0' ? '' : inputVal) + keyVal; $input.val(inputVal); } else { changeVal = inputVal === '' ? 0 : inputVal, step = $input.attr('step'); if (isDecimal) { step = parseFloat(step) || 0.1; changeVal = parseFloat(changeVal); } else { step = parseInt(step, 10) || 1; changeVal = parseInt(changeVal, 10); } // right function buttons switch($key.data('keycode')) { case '38 39': // ↑、→ 键增加 changeVal = _this.toFixedPrec(_this, $input, changeVal, step); break; case '37 40': // ↓、← 键减小 changeVal = _this.toFixedPrec(_this, $input, changeVal, -step); break; case 8: // Backspace 键退格 var valLength = inputVal.length; valLength && $input.val(inputVal.substring(0, valLength - 1)); return; case 46: // Delete 键清空 $input.val(''); return; } } $input.val(changeVal); }, /** 提示 */ tips: function($input, msg) { return layer.tips(msg, $input, { tips: [1, '#01AAED'], time: 2e3, anim: 6, zIndex: this.options.zIndex }); } }; exports('numinput', numberInput); });