首先申明一點,這個插件不是我寫的,是網上一個大神寫的,這是他的博客大家可以參考一下:http://www.cnblogs.com/xiangbing/p/mobile-select-area.html
===========================================分割線=========================
在下呢只是就這個插件做了一下簡單的適應性改進,需要的朋友可以往下看:
剛開始我也是在網上各種找插件,但是遇到一個問題就是項目要求樣式統一,但是各種五花八門的插件樣式都不一樣,於是索性就找一個插件然后稍作修改,就可以變成功能不同但是樣式統一的控件了,廢話不多講,開始:
1、源碼+demo |
它的github地址:https://github.com/tianxiangbing/mobile-select-area
它的demo演示:http://www.lovewebgames.com/jsmodule/mobile-select-area.html
2、使用方法 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <!--日期、地址控件 --> <script type="text/javascript" src="dist/jquery-1.12.3.min.js"></script> <link rel="stylesheet" type="text/css" href="dist/mobile-select-date.css"> <link rel="stylesheet" type="text/css" href="dist/dialog.css"> <script type="text/javascript" src="dist/dialog.js"></script> <script type="text/javascript" src="dist/mobile-select-date.js"></script> </head> <body> <div id="txt_date" style="width: 100px;height: 40px;background-color: #ccc;"> </div> <script type="text/javascript"> var selectDate = new MobileSelectDate(); selectDate.init({trigger:'#txt_date'}); </script> </body> </html>
/*注釋一下:dialog.css和插件js等文件時,如果引入的是壓縮版的,那么需要都引入壓縮版,如果不是壓縮版,那就都引入非壓縮版,我也不知道為什么,我試出來的,
還要引入zepto.js或者jquery.js文件*/
3、介紹一下API |
default:0||1
0為空,true時默認選中第一項,默認1
trigger:
觸發彈窗的DOM元素 ,可以是input或其他
value:
初始值,
level: int
級別數,默認是3級的
separator: ,
id值分隔符
eventName:tap|click
觸發事件名稱,默認click,使用zeptojs的可以用tap事件
data:
當data為json對象時可以直接解析,此時直接接收數組
當data為string發送ajax請求后返回json,格式如下:
{ "data": [{ "id": 1, "name": "浙江省", "child": [{ "id": "1", "name": "杭州市", "child": [{ "id": 1, "name": "濱江區" }] }] }, { "id": 2, "name": "江蘇省", "child": [{ "id": "1", "name": "南京", "child": [{ "id": 1, "name": "解放區" }] }] }, { "id": 3, "name": "湖北省" }] }
callback:function(scroller,text,value)
第一個是容器,第二個是選中后的text值,第三個參數是選中后的id。 並且this指向當前對象。 選中后的回調,默認有填充trigger的value值,以及賦值它后面緊跟着的hidden的value值,以逗號分隔id,空格分隔文字
4、重點來了,以下是我個人對這個插件的一些修改 |
剛剛大家都應該注意到我上傳的代碼跟源碼有些區別(源碼就在文章標題的demo演示地址里)
源碼默認的返回值是返回value,但有時候移動端里面需要將觸發元素換成其他DOM元素,例如div什么的,但是只有表單元素才有value屬性,當時我用這個插件的時候,直接把觸發元素換成div,發現返回值無法顯示,原因就是這個,div沒有value屬性,直接上代碼,修改后的 mobile-select-date.js
1 ; 2 (function(root, factory) { 3 //amd 4 if (typeof define === 'function' && define.amd) { 5 define(['$'], factory); 6 } else if (typeof exports === 'object') { //umd 7 module.exports = factory(); 8 } else { 9 root.MobileSelectDate = factory(window.Zepto || window.jQuery || $); 10 } 11 })(this, function($) { 12 //試圖寫個傻逼點的代碼 13 var MobileSelectDate = function() { 14 var rnd = Math.random().toString().replace('.', ''); 15 this.id = 'scroller_' + rnd; 16 this.scroller; 17 this.data; 18 this.index = 0; 19 this.value = [0, 0, 0]; 20 this.oldvalue; 21 this.oldtext; 22 this.text = ['', '', '']; 23 this.level = 3; 24 this.mtop = 30; 25 this.separator = ' '; 26 }; 27 MobileSelectDate.prototype = { 28 init: function(settings) { 29 this.settings = $.extend({}, settings); 30 this.separator = "/"; 31 var now = new Date(); 32 this.settings.value = this.settings.value || $(this.settings.trigger).val() || now.getFullYear() + "/" + ("0" + (now.getMonth() + 1)).slice(-2) + '/' + ("0" + (now.getDate())).slice(-2); 33 this.settings.value = this.settings.value.replace(/\//g, ','); 34 this.settings.text = this.settings.value.split(',') 35 this.settings.default==undefined ? this.default=1:this.default = 0 ;//0為空,1時默認選中第一項 36 this.trigger = $(this.settings.trigger); 37 this.trigger.attr("readonly", "readonly"); 38 this.value = (this.settings.value && this.settings.value.split(",")) || [0, 0, 0]; 39 this.text = this.settings.text || this.trigger.val().split(' ') || ['', '', '']; 40 this.oldvalue = this.value.concat([]); 41 this.oldtext = this.text.concat([]); 42 this.min = new Date(this.settings.min || "1900/01/01"); 43 this.settings.max ? this.max = new Date(this.settings.max) : this.max = new Date(); 44 this.getData(); 45 this.bindEvent(); 46 }, 47 //覆蓋數據方法,so easy 48 getData: function() { 49 var json = []; 50 for (var s = this.min.getFullYear(), l = this.max.getFullYear(); s <= l; s++) { 51 var obj = {}; 52 obj['id'] = obj['name'] = s; 53 obj.child = []; 54 for (var m = 1; m <= 12; m++) { 55 var o = {}; 56 o['id'] = o['name'] = ("0" + m).slice(-2); 57 o.child = []; 58 var days = new Date(s, m, 0).getDate(); 59 for (var d = 1; d <= days; d++) { 60 var j = {}; 61 j['id'] = j['name'] = ("0" + d).slice(-2); 62 if (!(m == this.max.getMonth() + 1 && s == this.max.getFullYear() && d > this.max.getDate())) { 63 o.child.push(j); 64 } 65 } 66 if (!(m > this.max.getMonth() + 1 && s == this.max.getFullYear())) { 67 obj.child.push(o); 68 } 69 } 70 json.push(obj) 71 } 72 this.data = json; 73 }, 74 bindEvent: function() { 75 var _this = this; 76 this.trigger.click(function(e) { 77 78 var settings,buttons; 79 if( _this.settings.position == "bottom"){ 80 settings ={ 81 position:"bottom", 82 width:"100%", 83 className:"ui-dialog-bottom", 84 animate:false 85 } 86 var buttons=[{ 87 'no': '取消' 88 },{ 89 'yes': '確定' 90 }]; 91 } 92 93 $.confirm('<div class="ui-scroller-mask"><div id="' + _this.id + '" class="ui-scroller"><div></div><div ></div><div></div><p></p></div></div>', buttons, function(t, c) { 94 if (t == "yes") { 95 _this.submit() 96 } 97 if (t == 'no') { 98 _this.cancel(); 99 } 100 this.dispose(); 101 }, $.extend({ 102 width: 320, 103 height: 215 104 },settings)); 105 106 _this.scroller = $('#' + _this.id); 107 _this.format(); 108 var start = 0, 109 end = 0 110 _this.scroller.children().bind('touchstart', function(e) { 111 start = (e.changedTouches || e.originalEvent.changedTouches)[0].pageY; 112 }); 113 _this.scroller.children().bind('touchmove', function(e) { 114 end = (e.changedTouches || e.originalEvent.changedTouches)[0].pageY; 115 var diff = end - start; 116 var dl = $(e.target).parent(); 117 if (dl[0].nodeName != "DL") { 118 return; 119 } 120 var top = parseInt(dl.css('top') || 0) + diff; 121 dl.css('top', top); 122 start = end; 123 return false; 124 }); 125 _this.scroller.children().bind('touchend', function(e) { 126 end = (e.changedTouches || e.originalEvent.changedTouches)[0].pageY; 127 var diff = end - start; 128 var dl = $(e.target).parent(); 129 if (dl[0].nodeName != "DL") { 130 return; 131 } 132 var i = $(dl.parent()).index(); 133 var top = parseInt(dl.css('top') || 0) + diff; 134 if (top > _this.mtop) { 135 top = _this.mtop; 136 } 137 if (top < -$(dl).height() + 60) { 138 top = -$(dl).height() + 60; 139 } 140 var mod = top / _this.mtop; 141 var mode = Math.round(mod); 142 var index = Math.abs(mode) + 1; 143 if (mode == 1) { 144 index = 0; 145 } 146 _this.value[i] = $(dl.children().get(index)).attr('ref'); 147 _this.value[i] == 0 ? _this.text[i] = "" : _this.text[i] = $(dl.children().get(index)).html(); 148 for (var j = _this.level - 1; j > i; j--) { 149 _this.value[j] = 0; 150 _this.text[j] = ""; 151 } 152 if (!$(dl.children().get(index)).hasClass('focus')) { 153 _this.format(); 154 } 155 $(dl.children().get(index)).addClass('focus').siblings().removeClass('focus'); 156 dl.css('top', mode * _this.mtop); 157 return false; 158 }); 159 return false; 160 }); 161 }, 162 format: function() { 163 var _this = this; 164 var child = _this.scroller.children(); 165 this.f(this.data); 166 }, 167 f: function(data) { 168 var _this = this; 169 var item = data; 170 if (!item) { 171 item = []; 172 }; 173 var str = '<dl><dd ref="0">——</dd>'; 174 var focus = 0, 175 childData, top = _this.mtop; 176 if (_this.index !== 0 && _this.value[_this.index - 1] == "0" && this.default == 0) { 177 str = '<dl><dd ref="0" class="focus">——</dd>'; 178 _this.value[_this.index] = 0; 179 _this.text[_this.index] = ""; 180 focus = 0; 181 } else { 182 if (_this.value[_this.index] == "0") { 183 str = '<dl><dd ref="0" class="focus">——</dd>'; 184 focus = 0; 185 } 186 if (item.length > 0 && this.default == 1) { 187 str = '<dl>'; 188 var pid = item[0].pid || 0; 189 var id = item[0].id || 0; 190 focus = item[0].id; 191 childData = item[0].child; 192 if(!_this.value[this.index ]){ 193 _this.value[this.index ] = id; 194 _this.text[this.index] = item[0].name; 195 } 196 str += '<dd pid="' + pid + '" class="' + cls + '" ref="' + id + '">' + item[0].name + '</dd>'; 197 } 198 for (var j = _this.default, len = item.length; j < len; j++) { 199 var pid = item[j].pid || 0; 200 var id = item[j].id || 0; 201 var cls = ''; 202 if (_this.value[_this.index] == id) { 203 cls = "focus"; 204 focus = id; 205 childData = item[j].child; 206 top = _this.mtop * (-(j - _this.default)); 207 }; 208 str += '<dd pid="' + pid + '" class="' + cls + '" ref="' + id + '">' + item[j].name + '</dd>'; 209 } 210 } 211 str += "</dl>"; 212 var newdom = $(str); 213 newdom.css('top', top); 214 var child = _this.scroller.children(); 215 $(child[_this.index]).html(newdom); 216 _this.index++; 217 if (_this.index > _this.level - 1) { 218 _this.index = 0; 219 return; 220 } 221 _this.f(childData); 222 }, 223 submit: function() { 224 this.oldvalue = this.value.concat([]); 225 this.oldtext = this.text.concat([]); 226 if (this.trigger[0].nodeType == 1) { 227 //input 228 this.trigger.text(this.text.join(this.separator)); 229 this.trigger.attr('data-value', this.value.join(',')); 230 } 231 this.trigger.next(':hidden').val(this.value.join(',')); 232 this.settings.callback && this.settings.callback(this.scroller); 233 }, 234 cancel: function() { 235 this.value = this.oldvalue.concat([]); 236 this.text = this.oldtext.concat([]); 237 } 238 } 239 return MobileSelectDate; 240 })
大家注意第228行,我把value值改成了text,就這,其實特別簡單,但是當時一直沒想到改源碼就可以實現,費了點時間,
最后,介紹一下這個插件如何拓展為自己的插件 |
這個插件的數據來源就是那個 data.json文件,里面的數據大家可以參考上邊介紹的書寫格式就可以,然后引入的時候注意一下目錄結構關系,