很早看到kissy首頁 有數量輸入控制元件,就隨便看了下功能 感覺也不怎麼難 所以也就試著自己也做了一個, 當然基本的功能和他們的一樣,只是用了自己的編碼思想來解決這麼一個問題。特此給大家分享下!kissy demo連結
個人編寫的 demo連結
下面來一步步分析下我當初寫程式碼的思路:
1. 首先是HTMl程式碼如下:
<h3>demo1:步長為0.8,下限為0, 預設是1</h3> <div id="demo1"></div> <button id="s40">設為40</button> <button id="increase">加一步</button> <button id="decrease">減一步</button>
而我開啟控制元件demo頁面時候 在火狐遊覽器firebug看到如下程式碼:
也就是說 <div id="demo1"></div> 裡面的span input程式碼是JS自動生成的。
2. 我JS程式碼做了如下事情:
1. 先判斷傳進來的容器型別判斷. 支援 demo1,#demo1,.demo1,$('#demo1') 這幾種容器型別的傳引數。如下程式碼判斷:
/* * 判斷傳進來的容器引數型別 */ _type: function(){ var self = this, _config = self.config, _cache = self.cache; if(_config.container != '') { if($.isPlainObject(_config.container)) { _config.container = _config.container; }else if(/^\./.test(_config.container)){ _config.container = $(_config.container); }else if(/^#/.test(_config.container)) { _config.container = $(_config.container); }else if($('#' + _config.container)) { _config.container = $('#' + _config.container); }else { alert('傳參的型別有誤!請重新傳參!'); } }else { return; } },
2. 渲染相對應容器裡面的程式碼,也就是span input標籤那些HTML程式碼。如下:
/* * 渲染html */ _renderHTML: function(){ var self = this, _config = self.config, _cache = self.cache; var html = ''; html += '<span class="'+_config.elCls+'-amount-wrap">' + '<input type="text" title="請輸入數字" value="'+_config.val+'" class="'+_config.elCls+'-amount-input"/>' + '<span class="'+_config.elCls+'-amount-increase"></span>' + '<span class="'+_config.elCls+'-amount-decrease"></span>' + '</span>'; $(_config.container).append(html); },
3. 繫結事件(包括點選,↑↓鍵操作等)。
1. 點選下一頁按鈕 或者↑ 操作時候 呼叫 增加方法:increase 程式碼如下:
/* * 增加方法 獲取input值 然後加個步長 (每次點選時候 判斷此值是否大於maxVal) * @method {increase public} */ increase: function() { var self = this, _config = self.config, _cache = self.cache; var inputVal = $.trim($('.' + _config.elCls + "-amount-input",_config.container).attr('value')); if(inputVal * 1 < _config.maxVal * 1) { var curVal = self._addFun(inputVal * 1,_config.step * 1); if(curVal >= _config.maxVal * 1) { curVal = _config.maxVal * 1; } $('.' + _config.elCls + "-amount-input",_config.container).val(curVal); $('.' + _config.elCls + "-amount-input",_config.container).attr('value',curVal); // 回撥 _config.nextFunc && $.isFunction(_config.nextFunc) && _config.nextFunc({value:curVal}); } },
2. 點選上一頁按鈕時候 或者 ↓鍵操作 時候 呼叫 decrease(減少方法)。如下程式碼:
/* * 減少方法 獲取input值 然後減去步長 (每次點選時候 判斷此值是否大於minVal) * @method {decrease public} */ decrease: function() { var self = this, _config = self.config; var inputVal = $.trim($('.' + _config.elCls + "-amount-input",_config.container).attr('value')); if(inputVal * 1 > _config.minVal * 1) { var curVal = self._subtraction(inputVal * 1, _config.step * 1); if(curVal <= _config.minVal * 1) { curVal = _config.minVal * 1; } $('.' + _config.elCls + "-amount-input",_config.container).val(curVal); $('.' + _config.elCls + "-amount-input",_config.container).attr('value',curVal); // 回撥 _config.prevFunc && $.isFunction(_config.prevFunc) && _config.prevFunc({value:curVal}); } },
3. 同樣支援在外部設定值 比如 我new一個例項後 我想點選一個按鈕後 直接讓此到某個值上 可以直接用new出來的例項呼叫setVal 方法。程式碼如下:
/* * 可以供外部直接設定值 * @method {setVal public} */ setVal: function(val) { var self = this, _config = self.config; // 簡單的判斷下 此值是否是數字型的 if(/\d/.test(val)) { $('.' + _config.elCls + "-amount-input",_config.container).val(val); $('.' + _config.elCls + "-amount-input",_config.container).attr('value',val); } },
4. 由於需求不斷的變增 所以配置項時候 步長有可能是小數 比如 點選一下 增加0.5步長 那麼在計算的時候 會有誤差(因為計算機儲存的是以2進位制儲存的),那麼處理這樣的方法用到了 上一篇文章 關於javascript中對浮點加,減,乘,除的精度分析 .
可配置的引數如下
下面貼下HTML程式碼如下:
<h3>demo1:步長為0.8,下限為0, 預設是1</h3> <div id="demo1"></div> <button id="s40">設為40</button> <button id="increase">加一步</button> <button id="decrease">減一步</button>
CSS程式碼:
.data-amount-wrap{position:relative;height:28px;display:block} .data-amount-input{ color: #666; font-size: 12px; margin:0; padding:3px 2px 0 3px; height:26px; border:1px solid; border-color:#848484 #E0E0E0 #E0E0E0 #848484; width:60px; line-height:26px; margin-left:16px; } .data-amount-increase,.data-amount-decrease{ position: absolute; /*width:16px;height: 14px;*/cursor: pointer; width:0;height:0;overflow:hidden; border-style:solid; } .data-amount-increase{left:85px;top:1px;border-width: 14px 0 14px 14px;border-color:transparent transparent transparent green;} .data-amount-decrease{left:0;top:1px;border-width: 14px 14px 14px 0;border-color:transparent red transparent transparent ;} button{margin:15px 0 0;}
JS程式碼如下:
/** * 數量輸入控制元件 */ function Amount(options) { this.config = { container : '', // 必須,控制元件插入的容器 預設為空 val : 1, // 初始值 預設為1 step : 1, // 一次改變的變化值 預設為1 minVal : 0, // 限下值 預設為0 maxVal : 100, // 限上值 預設為100 elCls : 'data', // 自定義的字首的類名 預設為data prevFunc : null, // 點選上一頁回撥函式 nextFunc : null // 點選下一頁回撥函式 }; this.cache = { decimalLen : 1 // 預設為1 }; this.init(options); } Amount.prototype = { constructor: Amount, init:function(options){ this.config = $.extend(this.config,options || {}); var self = this, _config = self.config, _cache = self.cache; // 先判斷傳進來的容器型別 self._type(); // 渲染HTML程式碼 self._renderHTML(); // 點選事件 self._bindEnv(); }, /* * 判斷傳進來的容器引數型別 */ _type: function(){ var self = this, _config = self.config, _cache = self.cache; if(_config.container != '') { if($.isPlainObject(_config.container)) { _config.container = _config.container; }else if(/^\./.test(_config.container)){ _config.container = $(_config.container); }else if(/^#/.test(_config.container)) { _config.container = $(_config.container); }else if($('#' + _config.container)) { _config.container = $('#' + _config.container); }else { alert('傳參的型別有誤!請重新傳參!'); } }else { return; } }, /* * 渲染html */ _renderHTML: function(){ var self = this, _config = self.config, _cache = self.cache; var html = ''; html += '<span class="'+_config.elCls+'-amount-wrap">' + '<input type="text" title="請輸入數字" value="'+_config.val+'" class="'+_config.elCls+'-amount-input"/>' + '<span class="'+_config.elCls+'-amount-increase"></span>' + '<span class="'+_config.elCls+'-amount-decrease"></span>' + '</span>'; $(_config.container).append(html); }, /* * 點選事件 */ _bindEnv: function() { var self = this, _config = self.config, _cache = self.cache; // 點選事件 事件代理 $(_config.container).unbind('click'); $(_config.container).bind('click',function(e){ var target = e.target; if($(target).hasClass(_config.elCls+"-amount-increase")) { // 執行increase method self.increase(); }else if($(target).hasClass(_config.elCls+"-amount-decrease")) { // 執行 decrease method self.decrease(); } }); // 鍵盤事件 鍵盤向上 鍵碼是38 向下是 40 $('.' + _config.elCls+"-amount-input",_config.container).keyup(function(e){ var keyCode = e.keyCode; if(keyCode == 40) { self.decrease(); }else if(keyCode == 38) { self.increase(); } }); }, /* * 增加方法 獲取input值 然後加個步長 (每次點選時候 判斷此值是否大於maxVal) * @method {increase public} */ increase: function() { var self = this, _config = self.config, _cache = self.cache; var inputVal = $.trim($('.' + _config.elCls + "-amount-input",_config.container).attr('value')); if(inputVal * 1 < _config.maxVal * 1) { var curVal = self._addFun(inputVal * 1,_config.step * 1); if(curVal >= _config.maxVal * 1) { curVal = _config.maxVal * 1; } $('.' + _config.elCls + "-amount-input",_config.container).val(curVal); $('.' + _config.elCls + "-amount-input",_config.container).attr('value',curVal); // 回撥 _config.nextFunc && $.isFunction(_config.nextFunc) && _config.nextFunc({value:curVal}); } }, /* * 減少方法 獲取input值 然後減去步長 (每次點選時候 判斷此值是否大於minVal) * @method {decrease public} */ decrease: function() { var self = this, _config = self.config; var inputVal = $.trim($('.' + _config.elCls + "-amount-input",_config.container).attr('value')); if(inputVal * 1 > _config.minVal * 1) { var curVal = self._subtraction(inputVal * 1, _config.step * 1); if(curVal <= _config.minVal * 1) { curVal = _config.minVal * 1; } $('.' + _config.elCls + "-amount-input",_config.container).val(curVal); $('.' + _config.elCls + "-amount-input",_config.container).attr('value',curVal); // 回撥 _config.prevFunc && $.isFunction(_config.prevFunc) && _config.prevFunc({value:curVal}); } }, /* * 可以供外部直接設定值 * @method {setVal public} */ setVal: function(val) { var self = this, _config = self.config; // 簡單的判斷下 此值是否是數字型的 if(/\d/.test(val)) { $('.' + _config.elCls + "-amount-input",_config.container).val(val); $('.' + _config.elCls + "-amount-input",_config.container).attr('value',val); } }, /* * JS加法 解決精度問題 * @method {_addFun private} * @param {arg1,arg2} int或者float,double */ _addFun: function(arg1,arg2) { var firstArg, lastArg, differ, m; try{ firstArg = arg1.toString().split('.')[1].length; } catch (e){ firstArg = 0; } try{ lastArg = arg2.toString().split('.')[1].length; } catch (e){ lastArg = 0; } differ = Math.abs(firstArg - lastArg); m = Math.pow(10,Math.max(firstArg,lastArg)); if(differ > 0) { var dm = Math.pow(10,differ); if(firstArg > lastArg) { arg1 = Number(arg1.toString().replace(".", "")); arg2 = Number(arg2.toString().replace(".", "")) * dm; }else { arg1 = Number(arg1.toString().replace(".", "")) * dm; arg2 = Number(arg2.toString().replace(".", "")); } }else { arg1 = Number(arg1.toString().replace(".", "")); arg2 = Number(arg2.toString().replace(".", "")); } return (arg1 + arg2) / m; }, /* * JS減法 解決精度問題 * @method {_subtraction private} * @param {arg1,arg2} int或者float,double */ _subtraction: function(arg1,arg2) { var firstArg, lastArg, differ, m; try{ firstArg = arg1.toString().split('.')[1].length; }catch (e){ firstArg = 0; } try{ lastArg = arg2.toString().split('.')[1].length; } catch (e){ lastArg = 0; } differ = Math.pow(10, Math.max(firstArg, lastArg)); m = (firstArg > lastArg) ? firstArg : lastArg; return ((arg1 * differ - arg2 * differ) / differ).toFixed(m); } };
初始化程式碼如下:
// 初始化 $(function(){ var a = new Amount({ container : '#demo1', step : '0.8', maxVal : '100' }) $('#s40').click(function(){ a.setVal(40); }); $("#increase").click(function(){ a.increase(); }); $("#decrease").click(function(){ a.decrease(); }); });