123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- /**
- * 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 = ['<style type="text/css">',
- '.', baseClassName, ' + .', keyClassName, ' { position: absolute; display: block; ',
- ' background-color: #f2f2f2; border-radius: 2px; border: 1px solid #e6e6e6; outline: none; }',
- '.', keyClassName, ' .layui-key-btn { font-family: Consolas; font-size: 17px; font-weight: 600; ',
- ' text-align: center; background-color: #ffffff; cursor: pointer; overflow: hidden; padding: 10px; }',
- '.', keyClassName, ' .layui-key-btn:active { background-color: #f2f2f2; }',
- '.layui-layer-tips kbd { display: inline-block; padding: 3px 5px; font-size: 11px;',
- ' line-height: 10px; color: #24292e; vertical-align: middle; background-color: #fafbfc;',
- ' border: 1px solid #d1d5da; border-radius: 3px; box-shadow: inset 0 -1px 0 #d1d5da; }',
- '</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 = [
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="49 97">1</div>',
- '</div>',
- '</div>',
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="50 98">2</div>',
- '</div>',
- '</div>',
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="51 99">3</div>',
- '</div>',
- '</div>'
- ].join(''),
- // 按钮 789
- btn789 = [
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="55 103">7</div>',
- '</div>',
- '</div>',
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="56 104">8</div>',
- '</div>',
- '</div>',
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="57 105">9</div>',
- '</div>',
- '</div>'
- ].join(''),
- /* 退格键 */
- backspace = [
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="8">',
- '<i class="layui-icon layui-icon-return"', _this.getTips('退格 <kbd>Backspace</kbd>'), '></i>',
- '</div>',
- '</div>',
- '</div>'
- ].join(''),
- /* 增加键 */
- add = [
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="38 39">',
- '<i class="layui-icon layui-icon-up"', _this.getTips('增加 <kbd>↑</kbd>'), '></i>',
- '</div>',
- '</div>',
- '</div>'
- ].join(''),
- /* 减小键 */
- reduce = [
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="37 40">',
- '<i class="layui-icon layui-icon-down"', _this.getTips('减小 <kbd>↓</kbd>'), '></i>',
- '</div>',
- '</div>',
- '</div>'
- ].join(''),
- /* 清空键 */
- reset = [
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="46">',
- '<i class="layui-icon layui-icon-refresh-1"', _this.getTips('清空 <kbd>Delete</kbd>'), '></i>',
- '</div>',
- '</div>',
- '</div>'
- ].join('');
- $input.after(['<div tabindex="0" hidefocus="true" class="', keyClassName,
- ' layui-unselect layui-anim layui-anim-upbit" ',
- 'style="width:', $input.width() + 10, 'px;">',
- '<div class="layui-row layui-col-space1">',
- _this.options.topBtns == 789 ? btn789 : btn123,
- _this.options.rightBtns ? backspace : '',
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="52 100">4</div>',
- '</div>',
- '</div>',
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="53 101">5</div>',
- '</div>',
- '</div>',
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="54 102">6</div>',
- '</div>',
- '</div>',
- _this.options.rightBtns ? add : '',
- _this.options.topBtns == 789 ? btn123 : btn789,
- _this.options.rightBtns ? reduce : '',
- _this.options.rightBtns ? '' : backspace,
- '<div class="layui-col-', sizeZero, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="48 96">0</div>',
- '</div>',
- '</div>',
- '<div class="layui-col-', sizeXS, '">',
- '<div class="layui-card">',
- '<div class="layui-key-btn" data-keycode="110 190">.</div>',
- '</div>',
- '</div>',
- _this.options.rightBtns ? reset : '',
- '</div>',
- '</div>'].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, '最小值为 <kbd>' + minVal + '</kbd>!');
- }
- if (value > maxVal) {
- value = _this.toFixedPrec(_this, $input, maxVal);
- _this.tips($input, '最大值为 <kbd>' + maxVal + '</kbd>!');
- }
- 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, '精确度为保留小数点后 <kbd>' + prec + '</kbd> 位!');
- 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);
- });
|