仿iphone日历插件(beta)
前言
小伙伴们好,很久不见了。最近工作进入正常期了,所以慢慢的悠闲的时间久没有了,所以不能每天水一篇了。
最近也在听师傅(http://home.cnblogs.com/u/aaronjs/)的教导开始阅读jquery源码了,怎么说呢,阅读的效果其实不是太好。
一来是时间断断续续的没有接上,今天读完明天又忘了,到第三天再读的话,就很多都忘记了;
二来是jquery其实还是有一定难度,加之篇幅也很长,所以读起来还是有一点吃力(我甚至有时候有种想睡的感觉),过了2星期才陆陆续续把core读完,结果很多都无法理解,再加油吧。
反正今年的目标就是把jquery读懂,时间多,不着急了。
时间比较紧未做兼容处理,请使用手机/或者使用chrome开启touch功能查看,后期补上兼容方案,以及修复BUG
关于工作
最近工作上需要在我们的网页上加入一些动画:
① 页面的切入切出的转场动画
② 模仿一个iphone的日历控件
转场动画做的时候其实碰到了很多坑,而且最后做出的效果也一般,因为既有的框架与dom结构已经出来了好久了,改不得,而且就算改了效果也不能保证好,所以暂时放下
这里说的仿iphone日历控件,不如说模仿一个单选框来的实在,而且我这里说是插件,完全就算标题党了,各位可以忽视,所以今日正题吧。
iphone的感觉
第一步我们要找到iphone的感觉,那么iphone是个什么感觉呢:
大概是这么个感觉,但是我做出来却变成了这种感觉,将就着看吧:
总体思路
PS:现在其实正在写功能代码,所以,现在我们是边写边做的,思路乱了各位请包涵
测试代码
这个代码很烂,各位就不要看了,我都不知道怎么写出来的,后面点整理吧,里面的CSS不想写就直接拿别人的用了
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 <style type="text/css"> 6 7 /*reset*/ 8 body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td,hr,button,article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{margin:0;padding:0} 9 body,button,input,select,textarea{font:normal 14px/1.5 Tahoma,"Lucida Grande",Verdana,"Microsoft YaHei",hei;} 10 article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section,iframe{display:block;} 11 h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:500;} 12 address,cite,dfn,em,var,i{font-style:normal;font-weight:normal;font-family:arial;} 13 ul,ol{list-style:none} 14 a{color:#000;text-decoration:none} 15 a:hover{text-decoration:underline;-webkit-transition:color .2s linear;-moz-transition:color .2s linear;-ms-transition:color .2s linear;-o-transition:color .2s linear;transition:color .2s linear;} 16 fieldset,img,button,input{border:0} 17 button,input,select,textarea{font-size:100%} 18 table{border-collapse:collapse;border-spacing:0} 19 input[type="button"],input[type="submit"]{-webkit-appearance:none;} 20 body{min-width:320px; background:#f5f5f5;overflow-x:hidden;-webkit-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-font-smoothing:subpixel-antialiased;-moz-user-select:none;color:#000;}:focus{outline:none;}.clearfix:after{clear:both;content:'.';display:block;height:0;visibility:hidden;line-height:0;}.clearfix{*zoom:1;}.fl{float:left;}.fr{float:right;}.clear{clear:both;}.overflow{overflow:hidden;}.ellips{white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}.ellips_line2,.ellips_line3{display: -webkit-box;-webkit-box-orient: vertical;overflow: hidden;}.ellips_line2{-webkit-line-clamp:2;}.ellips_line3{-webkit-line-clamp:3;}.pos_rel{position:relative;} 21 html,body,.h100{ height:100%; } 22 dfn{color:#ff9913; font-size:12px; font-weight:normal;} 23 /*-----------------------------------------common--------------------*/ 24 .i,.i_bef:before,.i_aft:after,.carlist li:before,.ok_crt:after{background:url(../img/style1/v2_bgs.png) no-repeat; background-size:175px 125px;} 25 .i_bef:before,.i_aft:after,.carlist li:before{position: absolute;content: "";} 26 .abs_size{-moz-box-sizing:border-box; -webkit-box-sizing:border-box; box-sizing:border-box;} 27 .opacity{opacity:0.7; filter:alpha(opacity=70);} 28 29 /*active*/ 30 .list_st_border li:active,.p_hinttxt:active,.search_cancel:active,.citylist dd:active{ background:#f8f8f8;} 31 .btn_yellow:active{background:#eb840f;} 32 33 /*layout*/ 34 .wrap{margin-top:48px;} 35 .wrap_pb{margin-top:48px; padding-bottom:45px;} 36 .p10{padding:10px;} 37 .hm{text-align:center;} 38 .break_all{word-break:break-all;} 39 .fix_b{position:fixed; bottom:0; left:0;z-index:9999;} 40 41 /*font bg color size*/ 42 h1{font:normal 1.286em/1.5 "";}/*18px*/ 43 h2{font:normal 1.143em/1.5 "";}/*16px*/ 44 h3{font:600 1em/1.5 "";}/*14px*/ 45 .price{margin-left:5px;} 46 .price i{margin-left:2px; font-size:1.286em;} 47 .greyfont{color:#686868;} 48 .greyfont1{color:#909090;} 49 .bggrey{height:100%; background:#f5f5f5;} 50 51 /*header*/ 52 header{position:fixed; top:0; left:0; z-index:9999; width:100%; height:48px;background-color:#1491c5;} 53 .returnico{position:absolute; left:0; top:0; width:68px; height:48px; background-color:#15a4d5;} 54 .returnico:before{left:25px;top:16px;width:12px;height:20px; background-position:0 0;} 55 .icon_phone,.icon_home{width:42px;height:100%;top:0;position:relative;float:right;} 56 .icon_phone:before{width:11px;height:20px;top:16px;right:12px;background-position:-115px -65px;} 57 .icon_home:before{width:20px;height:19px;top:16px;right:10px;background-position:-83px -66px;} 58 header i:active{opacity:0.7; filter:alpha(opacity=70);} 59 header h1{position:absolute; width:100%;line-height:48px; text-align:center; letter-spacing:2px; color: #fff;} 60 .header_r,.header_rs{position:absolute;z-index:9; top:0; right:0; line-height:48px; padding:0 15px; font-size:18px; background:#15a4d5; color:#fff;} 61 .header_rs{padding:0 5px; font-size:12px; } 62 63 /*background-position*/ 64 .select_n:before{width:20px;height:20px;background-position:-18px 0;} 65 .select_n.current:before{background-position:-44px 0;} 66 67 /*searchbox*/ 68 .search_wrap{overflow:hidden; padding:10px; background:#dfeaf1;} 69 .search_box{position:relative; float:left; width:100%;} 70 .search_input{width:100%; padding:0 10px 0 28px; line-height:30px; background-color:#fff; border-radius:4px; color:#ccc;} 71 .fdj:before,.fdj:after,.search_box:before,.search_box:after{position:absolute; content:""; z-index:9;} 72 .fdj:before,.search_box:before{left:5px; top:7px; width:12px; height:12px; border:1px solid #bcbcbc; border-radius:12px;} 73 .fdj:after,.search_box:after{left:19px; top:17px; width:1px; height:8px; background:#bcbcbc;} 74 .search_cancel{ display:none;float:left; width:20%; line-height:30px; text-align:center; font-size:16px;color:#1491c5; background:none; border:none;} 75 .close_icon{display:none; position:absolute; z-index:10; top:8px; right:4px; width:16px; height:16px; border-radius:30px; background:#b1b1b1;} 76 .close_icon:before,.close_icon:after{position:absolute; content:""; top:4px; left:7px; width:2px; height:8px; background:#fff; } 77 .close_icon:before{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);} 78 .fdj:after,.search_box:after,.close_icon:after{-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg);} 79 .search_focus .search_box{width:80%;} 80 .search_focus .close_icon, .search_focus .search_cancel{display:block;} 81 .search_input:focus{color:#000;} 82 83 /*tab*/ 84 .tab{ background-color:#f8f8f8; border-bottom:1px solid #dfdfdf;} 85 .tab li{float:left; width:50%; height:39px; line-height:39px; text-align:center; border-right:1px solid #dfdfdf;} 86 .tab li:last-child{border-right:none;} 87 .tab li.tabcrt{ background-color:#dfdfdf;} 88 89 .tab_b{ background-color:#f5f5f5; border-bottom:1px solid #c1c1c1;} 90 .tab_b li{float:left; width:50%; height:39px; line-height:39px; text-align:center;} 91 .tab_b li:last-child{border-right:none;} 92 .tab_b li.tabcrt{color:#1491c5; border-bottom:4px solid #1491c5;} 93 94 /*list*/ 95 .list_st_border{ background:#fff; border-bottom:none; border:1px solid #cfcfcf; } 96 .list_st_border li{position:relative;padding:0 10px; line-height:42px; border-bottom:1px solid #cfcfcf;} 97 .list_st_border li:last-child{border-bottom:none;} 98 99 .list_sli{padding:10px; overflow:hidden; border-bottom:1px solid #cfcfcf; background:#fff;} 100 .list_sli .list_sunit{float:left;} 101 102 .citylist{color:#000;} 103 .citylist dt,.citylist dd{padding-left:10px;border-bottom:1px solid #e2e2e2;} 104 .citylist dt{line-height:25px; background-color:#eaeaea;} 105 .citylist dd{position:relative; font-size:16px; line-height:43px; background-color:#fff;} 106 .citylist .ok_crt{color:#1491c5;} 107 .citylist .ok_crt:after{position:absolute;content:""; right:10px; top:50%; margin-top:-6px; width:12px; height:13px; background-position:-110px 0;} 108 109 110 /*arr*/ 111 .li_arr_r{position:relative;} 112 .arr_r{position:absolute;right:0px; top:50%; width:30px; height:30px; margin-top:-15px; } 113 .arr_r:before,.arr_r:after,.li_arr_r:before,.li_arr_r:after{position: absolute; left:15px; content: "";width:2px; height:7px; background-color:#909090;} 114 .arr_r:before,.li_arr_r:before{top:10px;-webkit-transform:rotate(-45deg); -moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg);} 115 .arr_r:after,.li_arr_r:after{top:15px;-webkit-transform:rotate(45deg); -moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);} 116 .li_arr_r:before,.li_arr_r:after{left:auto; right:10px; top:50%; margin-top:-5px;} 117 .li_arr_r:after{margin-top:0;} 118 119 /*p*/ 120 .p_grey{margin:10px 5px; font-size:13px; color:#989898;} 121 .p_grey_center{ text-align:center; margin:20px 5px; font-size:13px; color:#989898;} 122 .p_hinttxt{padding:20px 10px; text-align:center; font-size:16px; color:#1491c5;} 123 124 125 /*btn*/ 126 .btn_yellow,.btn_del{width:100%; height:44px; line-height:42px; padding:0 10px; color:#fff;} 127 .btn_yellow{background:#ff9913;} 128 .btn_del{background:#ca4345;text-align:center;font-size:1.2em;} 129 130 .btn_pay{padding:0 20px;height:44px;float:right;background:#ff7d13;color:#fff;} 131 .btn_pay:active{background:#ff7300;} 132 .room_num {position:absolute; right:10px; width:100px; height:30px; line-height:30px;color:#000;background-color: #fff; text-align:center;border:#bfbfbf 1px solid;} 133 .room_num i{position:absolute; width:30px; height:30px; text-align:center; font:normal 2em/28px "Arial";} 134 .room_num i:first-child{left:0;background:#f4f4f4;color:#d9d9d9;font:normal 2.8em/25px "Arial";} 135 .room_num i:last-child{right:0;background:#06a2d0;color:#fff;} 136 137 138 /*日历*/ 139 .cui_cldwrap{color:#000;} 140 .cui_cldweek{height:25px; overflow:hidden;font:normal 12px/24px "verdana";border-bottom:1px solid #c8c8c8;} 141 .cui_cldweek li{float:left; width:14%; text-align:center; } 142 .cui_cldweek li:first-child,.cui_cldweek li:last-child{width:15%; color:#acacac;} 143 .cui_cldmonth{height:35px;text-align:center;font:normal 16px/35px "verdana"; background:#fff;} 144 .cui_cldunit{margin-bottom:20px;} 145 .cui_cld_daybox{overflow:hidden; background:#fff;} 146 .cui_cld_daybox li{float:left; width:14%; height:45px; padding:4px 0; font:normal 12px/45px "verdana"; overflow:hidden; text-align:center;} 147 .cui_cld_daybox li:nth-child(7n),.cui_cld_daybox li:nth-child(7n+1){width:15%;} 148 .cui_cld_daypass{ background:#f7f7f7;} 149 .cui_cld_daycrt{background:#06a2d0; color:#fff;} 150 .cui_cld_dayfuture{background:#fff;} 151 .cui_cld_day_nocrtmonth{ visibility:hidden;} 152 .cui_cld_day_havetxt em{display:block; line-height:25px;} 153 .cui_cld_day_havetxt i{display:block;line-height:15px;} 154 .cui_cld_day_hint{color:#06a2d0;} 155 /*全局XXXX*/ 156 157 /*弹出蓝色框*/ 158 .cui-pop-box{background:#fff;} 159 .cui-text-center{text-align:center;} 160 .cui-pop-box .cui-hd{height:40px;line-height:40px;font-size:1.2em;color:#fff;background:#1491c5;padding:0 10px;position:relative;} 161 .cui-pop-box .cui-hd .cui-close{position:absolute;top:10px; right:10px; width:18px; height:18px;line-height:18px;border-radius:50%; background:#fff;color:#1491c5;text-align:center;font-weight:bold;} 162 .cui-error{width:150px;margin:auto;border-radius:5px;background:rgba(73,73,73,1);padding:10px;color:#fff;font-weight:700;text-align:center;word-break:break-all;} 163 .cui-select-view li{border-bottom:#dfdfdf 1px solid;padding:.8em 2em .8em .8em;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;position:relative;} 164 .cui-select-view li.current{color:#1084bc;} 165 .cui-select-view li:active{background:rgba(0,0,0,.05);} 166 .cui-select-view li.current:before,.cui-select-view li.current:after{position:absolute;content:"";background:#1084bc;height:3px;top:50%;border-radius:3px;} 167 .cui-select-view li.current:before{width:18px;right:10px;margin-top:-2px;-webkit-transform:rotate(-50deg);-moz-transform:rotate(-50deg);-ms-transform:rotate(-50deg);transform:rotate(-50deg);} 168 .cui-select-view li.current:after{width:9px;right:22px;margin-top:2px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);} 169 170 .cui-roller{width:100%;height:90px;overflow:hidden;position:relative;display: -webkit-box;display: -moz-box;display: -ms-flexbox;display: -webkit-flex;display: flex;} 171 .cui-roller .ul-list{height:100%;text-align:center;font-size:1.1em;line-height:30px;-webkit-box-flex: 1;-moz-box-flex: 1;-webkit-flex: 1;-ms-flex: 1;flex: 1;} 172 .cui-mask{position:absolute;z-index:3;top: 0;left: 0;width: 100%;height: 100%;pointer-events: none; 173 background: linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%); 174 background: -webkit-gradient(linear,left bottom,left top,from(#fff),color-stop(0.52,rgba(245,245,245,0)),color-stop(0.48,rgba(245,245,245,0)),to(#fff)); 175 background: -webkit-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%); 176 background: -moz-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%); 177 } 178 .cui-lines{width:100%;height:34px;position:absolute;top:50%;margin-top:-17px;border-top:#dfdfdf 1px solid;border-bottom:#dfdfdf 1px solid;} 179 .cui-roller-tips{color:#8d8d8d;padding:5px;text-align:center;} 180 .cui-roller-btns{background:#f6f5f5;padding:10px;text-align:center;} 181 .cui-roller-btns span{width:45%;display:inline-block;padding:10px 0;color:#fff;} 182 .cui-roller-btns span:active{opacity:.75;} 183 .cui-roller-btns .cui-btns-cancel{background:#a9a9a9;margin-right:5%;} 184 .cui-roller-btns .cui-btns-sure{background:#ff9913;} 185 186 </style> 187 <script src="../zepto.js" type="text/javascript"></script> 188 </head> 189 190 <body id="ctripPage" onselectstart="return false"> 191 192 <!--滚轮--> 193 <div class="cui-pop-box"> 194 <div class="cui-hd"><div class="cui-text-center">滚轮滚轮滚轮</div></div> 195 <div class="cui-bd"> 196 <div class="cui-roller"> 197 <ul class="ul-list" style=" position: absolute; width: 100%; z-index: 2; " > 198 <li>选项1</li> 199 <li>选项2</li> 200 <li>选项3</li> 201 <li>选项4</li> 202 <li>选项5</li> 203 <li>选项6</li> 204 <li>选项7</li> 205 <li>选项8</li> 206 <li>选项9</li> 207 <li>选项10</li> 208 <li>选项11</li> 209 <li>选项12</li> 210 <li>选项13</li> 211 <li>选项14</li> 212 <li>选项15</li> 213 <li>选项16</li> 214 <li>选项17</li> 215 <li>选项18</li> 216 <li>选项19</li> 217 <li>选项20</li> <li>选项1</li> 218 <li>选项2</li> 219 <li>选项3</li> 220 <li>选项4</li> 221 <li>选项5</li> 222 <li>选项6</li> 223 <li>选项7</li> 224 <li>选项8</li> 225 <li>选项9</li> 226 <li>选项10</li> 227 <li>选项11</li> 228 <li>选项12</li> 229 <li>选项13</li> 230 <li>选项14</li> 231 <li>选项15</li> 232 <li>选项16</li> 233 <li>选项17</li> 234 <li>选项18</li> 235 <li>选项19</li> 236 <li>选项20</li> 237 </ul> 238 239 <div class="cui-mask" style=""></div> 240 <div class="cui-lines"> </div> 241 </div> 242 <p class="cui-roller-tips">提示信息</p> 243 <div class="cui-roller-btns"> 244 <span class="cui-btns-cancel">取消</span><span class="cui-btns-sure">确定</span> 245 </div> 246 </div> 247 </div> 248 249 250 <script type="text/javascript"> 251 252 // var myScroll = new iScroll('wl1'); 253 254 255 256 257 var y1 = 0, y2 = 0; 258 var moveAble = false; 259 var dragEl = null; 260 var parent = $('.cui-roller'); 261 var offset; 262 var el_top = 0; 263 var o_top = 0; 264 var t1 = 0, t2 = 0; 265 var timer = null; 266 267 document.addEventListener("touchstart", touchStart, false); 268 document.addEventListener("touchend", touchEnd, false); 269 document.addEventListener("touchmove", touchMove, false); 270 271 function touchStart(e) { 272 t1 = e.timeStamp; 273 var srcElement = $(e.srcElement), pos; 274 dragEl = $(e.srcElement).parent(); 275 if (dragEl.hasClass('ul-list')) { 276 var pos = getMousePos(e.changedTouches[0]); 277 278 offset = dragEl.offset(); 279 y1 = pos.top - offset.top; 280 var top = parseFloat(dragEl.css('top')) || 0; 281 o_top = top; 282 y1 = y1 - parseFloat(top); 283 moveAble = true; 284 } 285 } 286 287 function touchMove(e) { 288 if (!dragEl || !moveAble) return false; 289 var pos = getMousePos(e.changedTouches[0]); 290 y2 = pos.top - y1 - offset.top; 291 292 if (timer) clearTimeout(timer); 293 294 295 el_top = y2; 296 dragEl.css('top', y2 + 'px'); 297 e.preventDefault(); 298 } 299 300 301 function touchEnd(e) { 302 t2 = e.timeStamp - t1; 303 var flag = o_top <= el_top ? 1 : -1; 304 var flag2 = el_top > 0 ? 1 : -1; 305 306 el_top = Math.abs(el_top); 307 var mod = el_top % 30; 308 el_top = (parseInt(el_top / 30) * 30 + (mod > 15 ? 30 : 0)) * flag2; 309 if (t2 >= 200) { 310 dragEl.animate({ 311 top: el_top + 'px' 312 }, 100, 'ease-in-out', function () { 313 if (el_top > 30) { 314 dragEl.animate({ 315 top: '30px' 316 }, 10, 'ease-in-out'); 317 } 318 if (el_top < 0 && (el_top + dragEl[0].scrollHeight < 60)) { 319 dragEl.animate({ 320 top: '-' + (dragEl[0].scrollHeight - 60) + 'px' 321 }, 10, 'ease-in-out'); 322 } 323 }); 324 } else { 325 var step = parseInt(t2 / 50); 326 console.log(t2, step); 327 328 var param = [10, 6, 4, 2]; 329 var _tmp = param[step] * 30 * flag; 330 _tmp = el_top + _tmp; 331 dragEl.animate({ 332 top: (_tmp) + 'px' 333 }, 100 + (param[step] * 50), 'ease-in-out', function () { 334 if (_tmp > 30) { 335 dragEl.animate({ 336 top: '30px' 337 }, 10, 'ease-in-out'); 338 } 339 if (_tmp < 0 && (_tmp + dragEl[0].scrollHeight < 60)) { 340 dragEl.animate({ 341 top: '-' + (dragEl[0].scrollHeight - 60) + 'px' 342 }, 10, 'ease-in-out'); 343 } 344 }); 345 346 347 } 348 moveAble = false; 349 } 350 351 function getMousePos(event) { 352 var top, left; 353 top = Math.max(document.body.scrollTop, document.documentElement.scrollTop); 354 left = Math.max(document.body.scrollLeft, document.documentElement.scrollLeft); 355 return { 356 top: top + event.clientY, 357 left: left + event.clientX 358 }; 359 }; 360 361 var s = ''; 362 363 </script> 364 365 </body> 366 </html>
demo请按照图示观看
http://sandbox.runjs.cn/show/dkf9dkwq
关于iscroll
最开始我们总是喜欢找一些已经存在了的解决方案来试试,这样就比较简单了,但是iscroll有一定问题就是他太大了。
最简单的压缩了都快10k了,所以直接给毙了,这里暂时就用不到他了。
zepto的touch事件
我是一个喜欢偷懒的人,我看着zepto有touch事件,本来想拿来直接用用谁知道。。。
1 // Zepto.js 2 // (c) 2010-2012 Thomas Fuchs 3 // Zepto.js may be freely distributed under the MIT license. 4 5 ;(function($){ 6 var touch = {}, 7 touchTimeout, tapTimeout, swipeTimeout, 8 longTapDelay = 750, longTapTimeout 9 10 function parentIfText(node) { 11 return 'tagName' in node ? node : node.parentNode 12 } 13 14 function swipeDirection(x1, x2, y1, y2) { 15 var xDelta = Math.abs(x1 - x2), yDelta = Math.abs(y1 - y2) 16 return xDelta >= yDelta ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down') 17 } 18 19 function longTap() { 20 longTapTimeout = null 21 if (touch.last) { 22 touch.el.trigger('longTap') 23 touch = {} 24 } 25 } 26 27 function cancelLongTap() { 28 if (longTapTimeout) clearTimeout(longTapTimeout) 29 longTapTimeout = null 30 } 31 32 function cancelAll() { 33 if (touchTimeout) clearTimeout(touchTimeout) 34 if (tapTimeout) clearTimeout(tapTimeout) 35 if (swipeTimeout) clearTimeout(swipeTimeout) 36 if (longTapTimeout) clearTimeout(longTapTimeout) 37 touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null 38 touch = {} 39 } 40 41 $(document).ready(function(){ 42 var now, delta 43 44 $(document.body) 45 .bind('touchstart', function(e){ 46 now = Date.now() 47 delta = now - (touch.last || now) 48 touch.el = $(parentIfText(e.touches[0].target)) 49 touchTimeout && clearTimeout(touchTimeout) 50 touch.x1 = e.touches[0].pageX 51 touch.y1 = e.touches[0].pageY 52 if (delta > 0 && delta <= 250) touch.isDoubleTap = true 53 touch.last = now 54 longTapTimeout = setTimeout(longTap, longTapDelay) 55 }) 56 .bind('touchmove', function(e){ 57 cancelLongTap() 58 touch.x2 = e.touches[0].pageX 59 touch.y2 = e.touches[0].pageY 60 if (Math.abs(touch.x1 - touch.x2) > 10) 61 e.preventDefault() 62 }) 63 .bind('touchend', function(e){ 64 cancelLongTap() 65 66 // swipe 67 if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) || 68 (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30)) 69 70 swipeTimeout = setTimeout(function() { 71 touch.el.trigger('swipe') 72 touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2))) 73 touch = {} 74 }, 0) 75 76 // normal tap 77 else if ('last' in touch) 78 79 // delay by one tick so we can cancel the 'tap' event if 'scroll' fires 80 // ('tap' fires before 'scroll') 81 tapTimeout = setTimeout(function() { 82 83 // trigger universal 'tap' with the option to cancelTouch() 84 // (cancelTouch cancels processing of single vs double taps for faster 'tap' response) 85 var event = $.Event('tap') 86 event.cancelTouch = cancelAll 87 touch.el.trigger(event) 88 89 // trigger double tap immediately 90 if (touch.isDoubleTap) { 91 touch.el.trigger('doubleTap') 92 touch = {} 93 } 94 95 // trigger single tap after 250ms of inactivity 96 else { 97 touchTimeout = setTimeout(function(){ 98 touchTimeout = null 99 touch.el.trigger('singleTap') 100 touch = {} 101 }, 250) 102 } 103 104 }, 0) 105 106 }) 107 .bind('touchcancel', cancelAll) 108 109 $(window).bind('scroll', cancelAll) 110 }) 111 112 ;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(m){ 113 $.fn[m] = function(callback){ return this.bind(m, callback) } 114 }) 115 })(Zepto)
这个就是zepto的touch事件,可以看到他只是对touchend有所监控,会触发一点点事件,所以和我们没有一毛钱关系
在此我便认命的自己敲下了以下代码:
1 document.addEventListener("touchstart", touchStart, false); 2 document.addEventListener("touchend", touchEnd, false); 3 document.addEventListener("touchmove", touchMove, false);
鼠标拖动
该功能的第一个技术点,便是元素跟着鼠标移动,拖到哪里就是哪里,这个大家都比较熟悉了,就不多说
touchend
当拖动结束时,我们要做很多后续的工作:
① 让选项进入既定的轨道
② 是否具有动画效果
③ 动画效果的步长等
PS:开始觉得有几个点可以说说,结果真的写出来却无话可说了,哎。。。。。。
经过以上版本,我们的粗制滥造版便出现了,就是以上的代码。
封装
于是我们就可以在这个基础上整理代码,封装起来了,请看下一步。
整理封装
首先,我们虽然写的不是插件,但是还是应该让他有插件的样子,来点简单的修饰吧。
经过一阶段的休整,我们的代码成了这个样子了:
1 (function () { 2 var ScrollRadio = function (opts) { 3 opts = opts || {}; 4 //容器元素 5 this.wrapper = opts.wrapper || $(document); 6 this.body = [ 7 '<div class="cui-roller">', 8 '<ul class="ul-list" style=" position: absolute; width: 100%; z-index: 2; " >', 9 '</ul>', 10 '<div class="cui-mask"></div>', 11 '<div class="cui-lines"> </div>', 12 '</div>' 13 ].join(''); 14 this.body = $(this.body); 15 16 //真正拖动的元素(现在是ul) 17 this.dragEl = this.body.find('.ul-list'); 18 //数据源 19 this.data = opts.data || []; 20 this._changed = opts.changed || null; 21 //当前选项索引 22 this.selectedIndex = 0; 23 //当前选项值 24 this.key = ''; 25 //当前选项显示的值 26 this.value = ''; 27 28 /* 29 定位实际需要用到的信息 30 暂时不考虑水平移动吧 31 */ 32 this.itemHeight = 0; //单个item高度 33 this.dragHeight = 0; //拖动元素高度 34 this.dragTop = 0; //拖动元素top 35 this.animateParam = [10, 8, 7, 6, 6, 6, 5, 5, 4, 2, 0]; //动画参数 36 this.timeGap = 0; //时间间隔 37 this.touchTime = 0; //开始时间 38 this.moveAble = false; //是否正在移动 39 this.moveState = 'up'; //移动状态,up right down left 40 this.oTop = 0; //拖动前的top值 41 this.curTop = 0; //当前容器top 42 this.mouseY = 0; //鼠标第一次点下时相对父容器的位置 43 44 45 this.init(); 46 }; 47 ScrollRadio.prototype = { 48 constructor: ScrollRadio, 49 init: function () { 50 this.initItem(); 51 this.wrapper.append(this.body); 52 this.initEventParam(); 53 this.bindEvent(); 54 55 return this; 56 }, 57 //增加数据 58 initItem: function () { 59 var _tmp, _data, i, k; 60 for (var i in this.data) { 61 _data = this.data[i] 62 _tmp = $('<li>' + (_data.val == undefined ? i : _data.val) + '</li>'); 63 _tmp.attr('data-index', i); 64 for (k in _data) { 65 _tmp.attr('data-' + k, _data[k]); 66 } 67 this.dragEl.append(_tmp); 68 } 69 }, 70 //初始化事件需要用到的参数信息 71 initEventParam: function () { 72 var offset = this.dragEl.offset(); 73 var itemOffset = this.dragEl.find('li').eq(0).offset(); 74 this.itemHeight = itemOffset.height 75 this.dragTop = offset.top; 76 this.dragHeight = this.dragEl[0].scrollHeight; 77 var s = ''; 78 }, 79 bindEvent: function () { 80 var scope = this; 81 document.addEventListener("touchstart", function (e) { 82 scope.touchStart.call(scope, e); 83 }, false); 84 document.addEventListener("touchend", function (e) { 85 scope.touchEnd.call(scope, e); 86 }, false); 87 document.addEventListener("touchmove", function (e) { 88 scope.touchMove.call(scope, e); 89 }, false); 90 }, 91 touchStart: function (e) { 92 //需要判断是否是拉取元素,此处需要递归验证,这里暂时不管 93 //!!!!!!!!此处不严谨 94 var el = $(e.srcElement).parent(), pos; 95 if (el.hasClass('ul-list')) { 96 this.touchTime = e.timeStamp; 97 //获取鼠标信息 98 pos = this.getMousePos(e.changedTouches[0]); 99 //注意,此处是相对位置 100 this.mouseY = pos.top - this.curTop; 101 this.moveAble = true; 102 } 103 }, 104 touchMove: function (e) { 105 if (!this.moveAble) return false; 106 var pos = this.getMousePos(e.changedTouches[0]); 107 //先获取相对容器的位置,在将两个鼠标位置相减 108 this.curTop = pos.top - this.mouseY; 109 110 this.dragEl.css('top', this.curTop + 'px'); 111 112 113 e.preventDefault(); 114 }, 115 touchEnd: function (e) { 116 //时间间隔 117 var scope = this; 118 this.timeGap = e.timeStamp - this.touchTime; 119 var flag = this.oTop <= this.curTop ? 1 : -1; //判断是向上还是向下滚动 120 var flag2 = this.curTop > 0 ? 1 : -1; //这个会影响后面的计算结果 121 this.moveState = flag > 0 ? 'up' : 'down'; 122 var ih = parseFloat(this.itemHeight); 123 var ih1 = ih / 2; 124 125 var top = Math.abs(this.curTop); 126 var mod = top % ih; 127 top = (parseInt(top / ih) * ih + (mod > ih1 ? ih : 0)) * flag2; 128 129 var step = parseInt(this.timeGap / 10 - 10); 130 step = step > 0 ? step : 0; 131 var speed = this.animateParam[step] || 0; 132 var increment = speed * ih * flag 133 top += increment; 134 this.dragEl.animate({ 135 top: top + 'px' 136 }, 100 + (speed * 20), 'ease-in-out', function () { 137 if (top > ih) { 138 scope.dragEl.animate({ 139 top: ih + 'px' 140 }, 10, 'ease-in-out'); 141 } 142 if (top < 0 && (top + scope.dragHeight < ih * 2)) { 143 scope.dragEl.animate({ 144 top: '-' + (scope.dragHeight - ih * 2) + 'px' 145 }, 10, 'ease-in-out'); 146 } 147 }); 148 149 console.log(this.timeGap, top, increment); 150 151 this.oTop = top; 152 this.curTop = top; 153 this.moveAble = false; 154 155 }, 156 setKey: function (k) { 157 158 }, 159 setVal: function (v) { }, 160 setIndex: function (i) { 161 162 }, 163 getSelected: function () { 164 165 }, 166 getByKey: function (k) { }, 167 getByVal: function (v) { }, 168 getByIndex: function (i) { }, 169 170 //选项改变时候触发 171 changed: function () { 172 173 }, 174 //获取鼠标信息 175 getMousePos: function (event) { 176 var top, left; 177 top = Math.max(document.body.scrollTop, document.documentElement.scrollTop); 178 left = Math.max(document.body.scrollLeft, document.documentElement.scrollLeft); 179 return { 180 top: top + event.clientY, 181 left: left + event.clientX 182 }; 183 } 184 185 }; 186 187 188 window.ScrollRadio = ScrollRadio; 189 190 })(); 191 192 var data = []; 193 for (var i = 0; i < 100; i++) { 194 var temp = { val: '选项-' + i }; 195 data.push(temp); 196 } 197 198 199 200 var myScroll = new ScrollRadio({ 201 wrapper: $('#ctripPage'), 202 data: data 203 }); 204 205 206 var s = '';
http://sandbox.runjs.cn/show/biousc1u
其中动画步长可以自己调节,选一个自己认为合适的,下面接着更新。
设置/获取
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 <style type="text/css"> 6 7 /*reset*/ 8 body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td,hr,button,article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{margin:0;padding:0} 9 body,button,input,select,textarea{font:normal 14px/1.5 Tahoma,"Lucida Grande",Verdana,"Microsoft YaHei",hei;} 10 article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section,iframe{display:block;} 11 h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:500;} 12 address,cite,dfn,em,var,i{font-style:normal;font-weight:normal;font-family:arial;} 13 ul,ol{list-style:none} 14 a{color:#000;text-decoration:none} 15 a:hover{text-decoration:underline;-webkit-transition:color .2s linear;-moz-transition:color .2s linear;-ms-transition:color .2s linear;-o-transition:color .2s linear;transition:color .2s linear;} 16 fieldset,img,button,input{border:0} 17 button,input,select,textarea{font-size:100%} 18 table{border-collapse:collapse;border-spacing:0} 19 input[type="button"],input[type="submit"]{-webkit-appearance:none;} 20 body{min-width:320px; background:#f5f5f5;overflow-x:hidden;-webkit-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-font-smoothing:subpixel-antialiased;-moz-user-select:none;color:#000;}:focus{outline:none;}.clearfix:after{clear:both;content:'.';display:block;height:0;visibility:hidden;line-height:0;}.clearfix{*zoom:1;}.fl{float:left;}.fr{float:right;}.clear{clear:both;}.overflow{overflow:hidden;}.ellips{white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}.ellips_line2,.ellips_line3{display: -webkit-box;-webkit-box-orient: vertical;overflow: hidden;}.ellips_line2{-webkit-line-clamp:2;}.ellips_line3{-webkit-line-clamp:3;}.pos_rel{position:relative;} 21 html,body,.h100{ height:100%; } 22 dfn{color:#ff9913; font-size:12px; font-weight:normal;} 23 /*-----------------------------------------common--------------------*/ 24 .i,.i_bef:before,.i_aft:after,.carlist li:before,.ok_crt:after{background:url(../img/style1/v2_bgs.png) no-repeat; background-size:175px 125px;} 25 .i_bef:before,.i_aft:after,.carlist li:before{position: absolute;content: "";} 26 .abs_size{-moz-box-sizing:border-box; -webkit-box-sizing:border-box; box-sizing:border-box;} 27 .opacity{opacity:0.7; filter:alpha(opacity=70);} 28 29 /*active*/ 30 .list_st_border li:active,.p_hinttxt:active,.search_cancel:active,.citylist dd:active{ background:#f8f8f8;} 31 .btn_yellow:active{background:#eb840f;} 32 33 /*layout*/ 34 .wrap{margin-top:48px;} 35 .wrap_pb{margin-top:48px; padding-bottom:45px;} 36 .p10{padding:10px;} 37 .hm{text-align:center;} 38 .break_all{word-break:break-all;} 39 .fix_b{position:fixed; bottom:0; left:0;z-index:9999;} 40 41 /*font bg color size*/ 42 h1{font:normal 1.286em/1.5 "";}/*18px*/ 43 h2{font:normal 1.143em/1.5 "";}/*16px*/ 44 h3{font:600 1em/1.5 "";}/*14px*/ 45 .price{margin-left:5px;} 46 .price i{margin-left:2px; font-size:1.286em;} 47 .greyfont{color:#686868;} 48 .greyfont1{color:#909090;} 49 .bggrey{height:100%; background:#f5f5f5;} 50 51 /*header*/ 52 header{position:fixed; top:0; left:0; z-index:9999; width:100%; height:48px;background-color:#1491c5;} 53 .returnico{position:absolute; left:0; top:0; width:68px; height:48px; background-color:#15a4d5;} 54 .returnico:before{left:25px;top:16px;width:12px;height:20px; background-position:0 0;} 55 .icon_phone,.icon_home{width:42px;height:100%;top:0;position:relative;float:right;} 56 .icon_phone:before{width:11px;height:20px;top:16px;right:12px;background-position:-115px -65px;} 57 .icon_home:before{width:20px;height:19px;top:16px;right:10px;background-position:-83px -66px;} 58 header i:active{opacity:0.7; filter:alpha(opacity=70);} 59 header h1{position:absolute; width:100%;line-height:48px; text-align:center; letter-spacing:2px; color: #fff;} 60 .header_r,.header_rs{position:absolute;z-index:9; top:0; right:0; line-height:48px; padding:0 15px; font-size:18px; background:#15a4d5; color:#fff;} 61 .header_rs{padding:0 5px; font-size:12px; } 62 63 /*background-position*/ 64 .select_n:before{width:20px;height:20px;background-position:-18px 0;} 65 .select_n.current:before{background-position:-44px 0;} 66 67 /*searchbox*/ 68 .search_wrap{overflow:hidden; padding:10px; background:#dfeaf1;} 69 .search_box{position:relative; float:left; width:100%;} 70 .search_input{width:100%; padding:0 10px 0 28px; line-height:30px; background-color:#fff; border-radius:4px; color:#ccc;} 71 .fdj:before,.fdj:after,.search_box:before,.search_box:after{position:absolute; content:""; z-index:9;} 72 .fdj:before,.search_box:before{left:5px; top:7px; width:12px; height:12px; border:1px solid #bcbcbc; border-radius:12px;} 73 .fdj:after,.search_box:after{left:19px; top:17px; width:1px; height:8px; background:#bcbcbc;} 74 .search_cancel{ display:none;float:left; width:20%; line-height:30px; text-align:center; font-size:16px;color:#1491c5; background:none; border:none;} 75 .close_icon{display:none; position:absolute; z-index:10; top:8px; right:4px; width:16px; height:16px; border-radius:30px; background:#b1b1b1;} 76 .close_icon:before,.close_icon:after{position:absolute; content:""; top:4px; left:7px; width:2px; height:8px; background:#fff; } 77 .close_icon:before{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);} 78 .fdj:after,.search_box:after,.close_icon:after{-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg);} 79 .search_focus .search_box{width:80%;} 80 .search_focus .close_icon, .search_focus .search_cancel{display:block;} 81 .search_input:focus{color:#000;} 82 83 /*tab*/ 84 .tab{ background-color:#f8f8f8; border-bottom:1px solid #dfdfdf;} 85 .tab li{float:left; width:50%; height:39px; line-height:39px; text-align:center; border-right:1px solid #dfdfdf;} 86 .tab li:last-child{border-right:none;} 87 .tab li.tabcrt{ background-color:#dfdfdf;} 88 89 .tab_b{ background-color:#f5f5f5; border-bottom:1px solid #c1c1c1;} 90 .tab_b li{float:left; width:50%; height:39px; line-height:39px; text-align:center;} 91 .tab_b li:last-child{border-right:none;} 92 .tab_b li.tabcrt{color:#1491c5; border-bottom:4px solid #1491c5;} 93 94 /*list*/ 95 .list_st_border{ background:#fff; border-bottom:none; border:1px solid #cfcfcf; } 96 .list_st_border li{position:relative;padding:0 10px; line-height:42px; border-bottom:1px solid #cfcfcf;} 97 .list_st_border li:last-child{border-bottom:none;} 98 99 .list_sli{padding:10px; overflow:hidden; border-bottom:1px solid #cfcfcf; background:#fff;} 100 .list_sli .list_sunit{float:left;} 101 102 .citylist{color:#000;} 103 .citylist dt,.citylist dd{padding-left:10px;border-bottom:1px solid #e2e2e2;} 104 .citylist dt{line-height:25px; background-color:#eaeaea;} 105 .citylist dd{position:relative; font-size:16px; line-height:43px; background-color:#fff;} 106 .citylist .ok_crt{color:#1491c5;} 107 .citylist .ok_crt:after{position:absolute;content:""; right:10px; top:50%; margin-top:-6px; width:12px; height:13px; background-position:-110px 0;} 108 109 110 /*arr*/ 111 .li_arr_r{position:relative;} 112 .arr_r{position:absolute;right:0px; top:50%; width:30px; height:30px; margin-top:-15px; } 113 .arr_r:before,.arr_r:after,.li_arr_r:before,.li_arr_r:after{position: absolute; left:15px; content: "";width:2px; height:7px; background-color:#909090;} 114 .arr_r:before,.li_arr_r:before{top:10px;-webkit-transform:rotate(-45deg); -moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg);} 115 .arr_r:after,.li_arr_r:after{top:15px;-webkit-transform:rotate(45deg); -moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);} 116 .li_arr_r:before,.li_arr_r:after{left:auto; right:10px; top:50%; margin-top:-5px;} 117 .li_arr_r:after{margin-top:0;} 118 119 /*p*/ 120 .p_grey{margin:10px 5px; font-size:13px; color:#989898;} 121 .p_grey_center{ text-align:center; margin:20px 5px; font-size:13px; color:#989898;} 122 .p_hinttxt{padding:20px 10px; text-align:center; font-size:16px; color:#1491c5;} 123 124 125 /*btn*/ 126 .btn_yellow,.btn_del{width:100%; height:44px; line-height:42px; padding:0 10px; color:#fff;} 127 .btn_yellow{background:#ff9913;} 128 .btn_del{background:#ca4345;text-align:center;font-size:1.2em;} 129 130 .btn_pay{padding:0 20px;height:44px;float:right;background:#ff7d13;color:#fff;} 131 .btn_pay:active{background:#ff7300;} 132 .room_num {position:absolute; right:10px; width:100px; height:30px; line-height:30px;color:#000;background-color: #fff; text-align:center;border:#bfbfbf 1px solid;} 133 .room_num i{position:absolute; width:30px; height:30px; text-align:center; font:normal 2em/28px "Arial";} 134 .room_num i:first-child{left:0;background:#f4f4f4;color:#d9d9d9;font:normal 2.8em/25px "Arial";} 135 .room_num i:last-child{right:0;background:#06a2d0;color:#fff;} 136 137 138 /*日历*/ 139 .cui_cldwrap{color:#000;} 140 .cui_cldweek{height:25px; overflow:hidden;font:normal 12px/24px "verdana";border-bottom:1px solid #c8c8c8;} 141 .cui_cldweek li{float:left; width:14%; text-align:center; } 142 .cui_cldweek li:first-child,.cui_cldweek li:last-child{width:15%; color:#acacac;} 143 .cui_cldmonth{height:35px;text-align:center;font:normal 16px/35px "verdana"; background:#fff;} 144 .cui_cldunit{margin-bottom:20px;} 145 .cui_cld_daybox{overflow:hidden; background:#fff;} 146 .cui_cld_daybox li{float:left; width:14%; height:45px; padding:4px 0; font:normal 12px/45px "verdana"; overflow:hidden; text-align:center;} 147 .cui_cld_daybox li:nth-child(7n),.cui_cld_daybox li:nth-child(7n+1){width:15%;} 148 .cui_cld_daypass{ background:#f7f7f7;} 149 .cui_cld_daycrt{background:#06a2d0; color:#fff;} 150 .cui_cld_dayfuture{background:#fff;} 151 .cui_cld_day_nocrtmonth{ visibility:hidden;} 152 .cui_cld_day_havetxt em{display:block; line-height:25px;} 153 .cui_cld_day_havetxt i{display:block;line-height:15px;} 154 .cui_cld_day_hint{color:#06a2d0;} 155 /*全局XXXX*/ 156 157 /*弹出蓝色框*/ 158 .cui-pop-box{background:#fff;} 159 .cui-text-center{text-align:center;} 160 .cui-pop-box .cui-hd{height:40px;line-height:40px;font-size:1.2em;color:#fff;background:#1491c5;padding:0 10px;position:relative;} 161 .cui-pop-box .cui-hd .cui-close{position:absolute;top:10px; right:10px; width:18px; height:18px;line-height:18px;border-radius:50%; background:#fff;color:#1491c5;text-align:center;font-weight:bold;} 162 .cui-error{width:150px;margin:auto;border-radius:5px;background:rgba(73,73,73,1);padding:10px;color:#fff;font-weight:700;text-align:center;word-break:break-all;} 163 .cui-select-view li{border-bottom:#dfdfdf 1px solid;padding:.8em 2em .8em .8em;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;position:relative;} 164 .cui-select-view li.current{color:#1084bc;} 165 .cui-select-view li:active{background:rgba(0,0,0,.05);} 166 .cui-select-view li.current:before,.cui-select-view li.current:after{position:absolute;content:"";background:#1084bc;height:3px;top:50%;border-radius:3px;} 167 .cui-select-view li.current:before{width:18px;right:10px;margin-top:-2px;-webkit-transform:rotate(-50deg);-moz-transform:rotate(-50deg);-ms-transform:rotate(-50deg);transform:rotate(-50deg);} 168 .cui-select-view li.current:after{width:9px;right:22px;margin-top:2px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);} 169 170 .cui-roller{width:100%;height:90px;overflow:hidden;position:relative;display: -webkit-box;display: -moz-box;display: -ms-flexbox;display: -webkit-flex;display: flex;} 171 .cui-roller .ul-list{height:100%;text-align:center;font-size:1.1em;line-height:30px;-webkit-box-flex: 1;-moz-box-flex: 1;-webkit-flex: 1;-ms-flex: 1;flex: 1;} 172 .cui-mask{position:absolute;z-index:3;top: 0;left: 0;width: 100%;height: 100%;pointer-events: none; 173 background: linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%); 174 background: -webkit-gradient(linear,left bottom,left top,from(#fff),color-stop(0.52,rgba(245,245,245,0)),color-stop(0.48,rgba(245,245,245,0)),to(#fff)); 175 background: -webkit-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%); 176 background: -moz-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%); 177 } 178 .cui-lines{width:100%;height:34px;position:absolute;top:50%;margin-top:-17px;border-top:#dfdfdf 1px solid;border-bottom:#dfdfdf 1px solid;} 179 .cui-roller-tips{color:#8d8d8d;padding:5px;text-align:center;} 180 .cui-roller-btns{background:#f6f5f5;padding:10px;text-align:center;} 181 .cui-roller-btns span{width:45%;display:inline-block;padding:10px 0;color:#fff;} 182 .cui-roller-btns span:active{opacity:.75;} 183 .cui-roller-btns .cui-btns-cancel{background:#a9a9a9;margin-right:5%;} 184 .cui-roller-btns .cui-btns-sure{background:#ff9913;} 185 186 </style> 187 188 <script id="others_zepto_10rc1" type="text/javascript" class="library" src="/js/sandbox/other/zepto.min.js"></script> 189 </head> 190 <body onselectstart="return false"> 191 <div class="cui-pop-box"> 192 <div class="cui-hd"> 193 <div class="cui-text-center"> 194 滚轮滚轮滚轮</div> 195 </div> 196 <div class="cui-bd"> 197 <div id="ctripPage"> 198 </div> 199 <p class="cui-roller-tips"> 200 提示信息</p> 201 <div class="cui-roller-btns"> 202 <span class="cui-btns-sure" id="set">设置值</span> <span class="cui-btns-sure" id="get"> 203 获取值</span> 204 </div> 205 </div> 206 </div> 207 <script type="text/javascript"> 208 209 // var myScroll = new iScroll('wl1'); 210 211 (function () { 212 //!!!由于动画原因,获取值可能会出现不准确的情况,比如正在动画却已经取值了 213 //所以设置了一个冷却时间,在冷却时间的情况下设置值等操作不能进行 214 //为了保证唯一性,全部使用index作为索引算了 215 var ScrollRadio = function (opts) { 216 opts = opts || {}; 217 //容器元素 218 this.wrapper = opts.wrapper || $(document); 219 this.body = [ 220 '<div class="cui-roller">', 221 '<ul class="ul-list" style=" position: absolute; width: 100%; z-index: 2; " >', 222 '</ul>', 223 '<div class="cui-mask"></div>', 224 '<div class="cui-lines"> </div>', 225 '</div>' 226 ].join(''); 227 this.body = $(this.body); 228 229 //真正拖动的元素(现在是ul) 230 this.dragEl = this.body.find('.ul-list'); 231 //数据源 232 this.data = opts.data || []; 233 this._changed = opts.changed || null; 234 //当前选项索引默认选择2项 235 this.selectedIndex = 1; 236 237 //当前选项值 238 // this.key = ''; 239 //当前选项显示的值 240 // this.value = ''; 241 242 /* 243 定位实际需要用到的信息 244 暂时不考虑水平移动吧 245 */ 246 this.itemHeight = 0; //单个item高度 247 this.dragHeight = 0; //拖动元素高度 248 this.dragTop = 0; //拖动元素top 249 this.animateParam = [10, 6, 2, 1, 0, 0, 0, 0, 0, 0, 0]; //动画参数 250 this.timeGap = 0; //时间间隔 251 this.touchTime = 0; //开始时间 252 this.moveAble = false; //是否正在移动 253 this.moveState = 'up'; //移动状态,up right down left 254 this.oTop = 0; //拖动前的top值 255 this.curTop = 0; //当前容器top 256 this.mouseY = 0; //鼠标第一次点下时相对父容器的位置 257 this.cooling = false; //是否处于冷却时间 258 259 this.init(); 260 }; 261 ScrollRadio.prototype = { 262 constructor: ScrollRadio, 263 init: function () { 264 this.initItem(); 265 this.wrapper.append(this.body); 266 this.initEventParam(); 267 this.bindEvent(); 268 269 return this; 270 }, 271 //增加数据 272 initItem: function () { 273 var _tmp, _data, i, k; 274 for (var i in this.data) { 275 _data = this.data[i] 276 _tmp = $('<li>' + (_data.val == undefined ? i : _data.val) + '</li>'); 277 _tmp.attr('data-index', i); 278 for (k in _data) { 279 _tmp.attr('data-' + k, _data[k]); 280 } 281 this.dragEl.append(_tmp); 282 } 283 }, 284 //初始化事件需要用到的参数信息 285 initEventParam: function () { 286 var offset = this.dragEl.offset(); 287 var itemOffset = this.dragEl.find('li').eq(0).offset(); 288 this.itemHeight = itemOffset.height 289 this.dragTop = offset.top; 290 this.dragHeight = this.dragEl[0].scrollHeight; 291 var s = ''; 292 }, 293 bindEvent: function () { 294 var scope = this; 295 document.addEventListener("touchstart", function (e) { 296 scope.touchStart.call(scope, e); 297 }, false); 298 document.addEventListener("touchend", function (e) { 299 scope.touchEnd.call(scope, e); 300 }, false); 301 document.addEventListener("touchmove", function (e) { 302 scope.touchMove.call(scope, e); 303 }, false); 304 }, 305 touchStart: function (e) { 306 if (this.cooling) return false; //冷却时间不能开始 307 308 //需要判断是否是拉取元素,此处需要递归验证,这里暂时不管 309 //!!!!!!!!此处不严谨 310 var el = $(e.srcElement).parent(), pos; 311 if (el.hasClass('ul-list')) { 312 this.moveAble = true; 313 314 this.touchTime = e.timeStamp; 315 //获取鼠标信息 316 pos = this.getMousePos(e.changedTouches[0]); 317 //注意,此处是相对位置,注意该处还与动画有关,所以高度必须动态计算 318 //可以设置一个冷却时间参数,但想想还是算了 319 //最后还是使用了冷却时间 320 // var top = parseFloat(this.dragEl.css('top')) || 0; 321 // this.mouseY = pos.top - top; 322 this.mouseY = pos.top - this.curTop; 323 this.moveAble = true; 324 } 325 }, 326 touchMove: function (e) { 327 if (!this.moveAble) return false; 328 var pos = this.getMousePos(e.changedTouches[0]); 329 //先获取相对容器的位置,在将两个鼠标位置相减 330 this.curTop = pos.top - this.mouseY; 331 this.dragEl.css('top', this.curTop + 'px'); 332 e.preventDefault(); 333 }, 334 touchEnd: function (e) { 335 if (!this.moveAble) return false; 336 this.cooling = true; //开启冷却时间 337 338 //时间间隔 339 var scope = this; 340 this.timeGap = e.timeStamp - this.touchTime; 341 var flag = this.oTop <= this.curTop ? 1 : -1; //判断是向上还是向下滚动 342 var flag2 = this.curTop > 0 ? 1 : -1; //这个会影响后面的计算结果 343 this.moveState = flag > 0 ? 'up' : 'down'; 344 var ih = parseFloat(this.itemHeight); 345 var ih1 = ih / 2; 346 347 var top = Math.abs(this.curTop); 348 var mod = top % ih; 349 top = (parseInt(top / ih) * ih + (mod > ih1 ? ih : 0)) * flag2; 350 351 var step = parseInt(this.timeGap / 50); 352 step = step > 0 ? step : 0; 353 var speed = this.animateParam[step] || 0; 354 var increment = speed * ih * flag 355 top += increment; 356 //!!!此处动画可能导致数据不同步,后期改造需要加入冷却时间 357 if (this.oTop != this.curTop) { 358 this.dragEl.animate({ 359 top: top + 'px' 360 }, 100 + (speed * 20), 'ease-out', function () { 361 var _top = top, t = false; ; 362 if (top > ih) { 363 _top = ih; 364 t = true; 365 } 366 if (top < 0 && (top + scope.dragHeight < ih * 2)) { 367 t = true; 368 _top = (scope.dragHeight - ih * 2) * (-1); 369 } 370 if (t) { 371 scope.dragEl.animate({ 372 top: _top + 'px' 373 }, 10, 'ease-in-out', function () { 374 scope.oTop = _top; 375 scope.curTop = _top; 376 scope.cooling = false; //关闭冷却时间 377 scope.onTouchEnd(); 378 }); 379 } else { 380 scope.cooling = false; //关闭冷却时间 381 scope.oTop = top; 382 scope.curTop = top; 383 scope.onTouchEnd(); 384 } 385 }); 386 } else { 387 this.cooling = false; //关闭冷却时间 388 this.onTouchEnd(); 389 } 390 this.moveAble = false; 391 }, 392 onTouchEnd: function () { 393 var i = parseInt((this.curTop - this.itemHeight) / parseFloat(this.itemHeight)); 394 this.selectedIndex = Math.abs(i); 395 var secItem = this.data[this.selectedIndex]; 396 //触发变化事件 397 var changed = this._changed; 398 if (changed && typeof changed == 'function') { 399 changed.call(this, secItem); 400 } 401 console.log(this.selectedIndex, secItem); 402 }, 403 setKey: function (k) { }, 404 setVal: function (v) { }, 405 setIndex: function (i) { 406 var i = parseInt(i); 407 if (i >= this.data.length || i < 0) return false; 408 409 this.selectedIndex = i; 410 this.curTop = (i * this.itemHeight * (-1) + this.itemHeight); 411 this.dragEl.css('top', this.curTop + 'px'); 412 }, 413 getSelected: function () { 414 return this.data[this.selectedIndex]; 415 }, 416 getByKey: function (k) { }, 417 getByVal: function (v) { }, 418 getByIndex: function (i) { }, 419 //获取鼠标信息 420 getMousePos: function (event) { 421 var top, left; 422 top = Math.max(document.body.scrollTop, document.documentElement.scrollTop); 423 left = Math.max(document.body.scrollLeft, document.documentElement.scrollLeft); 424 return { 425 top: top + event.clientY, 426 left: left + event.clientX 427 }; 428 } 429 }; 430 window.ScrollRadio = ScrollRadio; 431 432 })(); 433 434 var data = []; 435 for (var i = 0; i < 20; i++) { 436 var temp = { val: '选项-' + i }; 437 data.push(temp); 438 } 439 440 441 442 var myScroll = new ScrollRadio({ 443 wrapper: $('#ctripPage'), 444 data: data 445 }); 446 447 $('#set').click(function () { 448 var i = prompt("请输入索引值") 449 if (i != null && i != "") { 450 myScroll.setIndex(i); 451 } 452 }); 453 454 $('#get').click(function () { 455 var d = myScroll.getSelected(); 456 var str = ''; 457 for (var k in d) { 458 str += k + ': ' + d[k] + ','; 459 } 460 alert(str); 461 }); 462 463 var s = ''; 464 465 </script> 466 </body> 467 </html>
我们这里简单看看代码:
1 (function () { 2 //!!!由于动画原因,获取值可能会出现不准确的情况,比如正在动画却已经取值了 3 //所以设置了一个冷却时间,在冷却时间的情况下设置值等操作不能进行 4 //为了保证唯一性,全部使用index作为索引算了 5 var ScrollRadio = function (opts) { 6 opts = opts || {}; 7 //容器元素 8 this.wrapper = opts.wrapper || $(document); 9 this.body = [ 10 '<div class="cui-roller">', 11 '<ul class="ul-list" style=" position: absolute; width: 100%; z-index: 2; " >', 12 '</ul>', 13 '<div class="cui-mask"></div>', 14 '<div class="cui-lines"> </div>', 15 '</div>' 16 ].join(''); 17 this.body = $(this.body); 18 19 //真正拖动的元素(现在是ul) 20 this.dragEl = this.body.find('.ul-list'); 21 //数据源 22 this.data = opts.data || []; 23 this._changed = opts.changed || null; 24 //当前选项索引默认选择2项 25 this.selectedIndex = 1; 26 27 //当前选项值 28 // this.key = ''; 29 //当前选项显示的值 30 // this.value = ''; 31 32 /* 33 定位实际需要用到的信息 34 暂时不考虑水平移动吧 35 */ 36 this.itemHeight = 0; //单个item高度 37 this.dragHeight = 0; //拖动元素高度 38 this.dragTop = 0; //拖动元素top 39 this.animateParam = [10, 6, 2, 1, 0, 0, 0, 0, 0, 0, 0]; //动画参数 40 this.timeGap = 0; //时间间隔 41 this.touchTime = 0; //开始时间 42 this.moveAble = false; //是否正在移动 43 this.moveState = 'up'; //移动状态,up right down left 44 this.oTop = 0; //拖动前的top值 45 this.curTop = 0; //当前容器top 46 this.mouseY = 0; //鼠标第一次点下时相对父容器的位置 47 this.cooling = false; //是否处于冷却时间 48 49 this.init(); 50 }; 51 ScrollRadio.prototype = { 52 constructor: ScrollRadio, 53 init: function () { 54 this.initItem(); 55 this.wrapper.append(this.body); 56 this.initEventParam(); 57 this.bindEvent(); 58 59 return this; 60 }, 61 //增加数据 62 initItem: function () { 63 var _tmp, _data, i, k; 64 for (var i in this.data) { 65 _data = this.data[i] 66 _tmp = $('<li>' + (_data.val == undefined ? i : _data.val) + '</li>'); 67 _tmp.attr('data-index', i); 68 for (k in _data) { 69 _tmp.attr('data-' + k, _data[k]); 70 } 71 this.dragEl.append(_tmp); 72 } 73 }, 74 //初始化事件需要用到的参数信息 75 initEventParam: function () { 76 var offset = this.dragEl.offset(); 77 var itemOffset = this.dragEl.find('li').eq(0).offset(); 78 this.itemHeight = itemOffset.height 79 this.dragTop = offset.top; 80 this.dragHeight = this.dragEl[0].scrollHeight; 81 var s = ''; 82 }, 83 bindEvent: function () { 84 var scope = this; 85 document.addEventListener("touchstart", function (e) { 86 scope.touchStart.call(scope, e); 87 }, false); 88 document.addEventListener("touchend", function (e) { 89 scope.touchEnd.call(scope, e); 90 }, false); 91 document.addEventListener("touchmove", function (e) { 92 scope.touchMove.call(scope, e); 93 }, false); 94 }, 95 touchStart: function (e) { 96 if (this.cooling) return false; //冷却时间不能开始 97 98 //需要判断是否是拉取元素,此处需要递归验证,这里暂时不管 99 //!!!!!!!!此处不严谨 100 var el = $(e.srcElement).parent(), pos; 101 if (el.hasClass('ul-list')) { 102 this.moveAble = true; 103 104 this.touchTime = e.timeStamp; 105 //获取鼠标信息 106 pos = this.getMousePos(e.changedTouches[0]); 107 //注意,此处是相对位置,注意该处还与动画有关,所以高度必须动态计算 108 //可以设置一个冷却时间参数,但想想还是算了 109 //最后还是使用了冷却时间 110 // var top = parseFloat(this.dragEl.css('top')) || 0; 111 // this.mouseY = pos.top - top; 112 this.mouseY = pos.top - this.curTop; 113 this.moveAble = true; 114 } 115 }, 116 touchMove: function (e) { 117 if (!this.moveAble) return false; 118 var pos = this.getMousePos(e.changedTouches[0]); 119 //先获取相对容器的位置,在将两个鼠标位置相减 120 this.curTop = pos.top - this.mouseY; 121 this.dragEl.css('top', this.curTop + 'px'); 122 e.preventDefault(); 123 }, 124 touchEnd: function (e) { 125 if (!this.moveAble) return false; 126 this.cooling = true; //开启冷却时间 127 128 //时间间隔 129 var scope = this; 130 this.timeGap = e.timeStamp - this.touchTime; 131 var flag = this.oTop <= this.curTop ? 1 : -1; //判断是向上还是向下滚动 132 var flag2 = this.curTop > 0 ? 1 : -1; //这个会影响后面的计算结果 133 this.moveState = flag > 0 ? 'up' : 'down'; 134 var ih = parseFloat(this.itemHeight); 135 var ih1 = ih / 2; 136 137 var top = Math.abs(this.curTop); 138 var mod = top % ih; 139 top = (parseInt(top / ih) * ih + (mod > ih1 ? ih : 0)) * flag2; 140 141 var step = parseInt(this.timeGap / 50); 142 step = step > 0 ? step : 0; 143 var speed = this.animateParam[step] || 0; 144 var increment = speed * ih * flag 145 top += increment; 146 //!!!此处动画可能导致数据不同步,后期改造需要加入冷却时间 147 if (this.oTop != this.curTop) { 148 this.dragEl.animate({ 149 top: top + 'px' 150 }, 100 + (speed * 20), 'ease-out', function () { 151 var _top = top, t = false; ; 152 if (top > ih) { 153 _top = ih; 154 t = true; 155 } 156 if (top < 0 && (top + scope.dragHeight < ih * 2)) { 157 t = true; 158 _top = (scope.dragHeight - ih * 2) * (-1); 159 } 160 if (t) { 161 scope.dragEl.animate({ 162 top: _top + 'px' 163 }, 10, 'ease-in-out', function () { 164 scope.oTop = _top; 165 scope.curTop = _top; 166 scope.cooling = false; //关闭冷却时间 167 scope.onTouchEnd(); 168 }); 169 } else { 170 scope.cooling = false; //关闭冷却时间 171 scope.oTop = top; 172 scope.curTop = top; 173 scope.onTouchEnd(); 174 } 175 }); 176 } else { 177 this.cooling = false; //关闭冷却时间 178 this.onTouchEnd(); 179 } 180 this.moveAble = false; 181 }, 182 onTouchEnd: function () { 183 var i = parseInt((this.curTop - this.itemHeight) / parseFloat(this.itemHeight)); 184 this.selectedIndex = Math.abs(i); 185 var secItem = this.data[this.selectedIndex]; 186 //触发变化事件 187 var changed = this._changed; 188 if (changed && typeof changed == 'function') { 189 changed.call(this, secItem); 190 } 191 console.log(this.selectedIndex, secItem); 192 }, 193 setKey: function (k) { }, 194 setVal: function (v) { }, 195 setIndex: function (i) { 196 var i = parseInt(i); 197 if (i >= this.data.length || i < 0) return false; 198 199 this.selectedIndex = i; 200 this.curTop = (i * this.itemHeight * (-1) + this.itemHeight); 201 this.dragEl.css('top', this.curTop + 'px'); 202 }, 203 getSelected: function () { 204 return this.data[this.selectedIndex]; 205 }, 206 getByKey: function (k) { }, 207 getByVal: function (v) { }, 208 getByIndex: function (i) { }, 209 //获取鼠标信息 210 getMousePos: function (event) { 211 var top, left; 212 top = Math.max(document.body.scrollTop, document.documentElement.scrollTop); 213 left = Math.max(document.body.scrollLeft, document.documentElement.scrollLeft); 214 return { 215 top: top + event.clientY, 216 left: left + event.clientX 217 }; 218 } 219 }; 220 window.ScrollRadio = ScrollRadio; 221 222 })();
以上代码基本框架都出来了,也有注释,有兴趣的朋友自己看看,我们现在进行最后一步了,将日历搞上去,老夫来不起了。。。
日历插件:)
http://sandbox.runjs.cn/show/prii13pm
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 <style type="text/css"> 6 7 /*reset*/ 8 body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td,hr,button,article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{margin:0;padding:0} 9 body,button,input,select,textarea{font:normal 14px/1.5 Tahoma,"Lucida Grande",Verdana,"Microsoft YaHei",hei;} 10 article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section,iframe{display:block;} 11 h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:500;} 12 address,cite,dfn,em,var,i{font-style:normal;font-weight:normal;font-family:arial;} 13 ul,ol{list-style:none} 14 a{color:#000;text-decoration:none} 15 a:hover{text-decoration:underline;-webkit-transition:color .2s linear;-moz-transition:color .2s linear;-ms-transition:color .2s linear;-o-transition:color .2s linear;transition:color .2s linear;} 16 fieldset,img,button,input{border:0} 17 button,input,select,textarea{font-size:100%} 18 table{border-collapse:collapse;border-spacing:0} 19 input[type="button"],input[type="submit"]{-webkit-appearance:none;} 20 body{min-width:320px; background:#f5f5f5;overflow-x:hidden;-webkit-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-font-smoothing:subpixel-antialiased;-moz-user-select:none;color:#000;}:focus{outline:none;}.clearfix:after{clear:both;content:'.';display:block;height:0;visibility:hidden;line-height:0;}.clearfix{*zoom:1;}.fl{float:left;}.fr{float:right;}.clear{clear:both;}.overflow{overflow:hidden;}.ellips{white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}.ellips_line2,.ellips_line3{display: -webkit-box;-webkit-box-orient: vertical;overflow: hidden;}.ellips_line2{-webkit-line-clamp:2;}.ellips_line3{-webkit-line-clamp:3;}.pos_rel{position:relative;} 21 html,body,.h100{ height:100%; } 22 dfn{color:#ff9913; font-size:12px; font-weight:normal;} 23 /*-----------------------------------------common--------------------*/ 24 .i,.i_bef:before,.i_aft:after,.carlist li:before,.ok_crt:after{background:url(../img/style1/v2_bgs.png) no-repeat; background-size:175px 125px;} 25 .i_bef:before,.i_aft:after,.carlist li:before{position: absolute;content: "";} 26 .abs_size{-moz-box-sizing:border-box; -webkit-box-sizing:border-box; box-sizing:border-box;} 27 .opacity{opacity:0.7; filter:alpha(opacity=70);} 28 29 /*active*/ 30 .list_st_border li:active,.p_hinttxt:active,.search_cancel:active,.citylist dd:active{ background:#f8f8f8;} 31 .btn_yellow:active{background:#eb840f;} 32 33 /*layout*/ 34 .wrap{margin-top:48px;} 35 .wrap_pb{margin-top:48px; padding-bottom:45px;} 36 .p10{padding:10px;} 37 .hm{text-align:center;} 38 .break_all{word-break:break-all;} 39 .fix_b{position:fixed; bottom:0; left:0;z-index:9999;} 40 41 /*font bg color size*/ 42 h1{font:normal 1.286em/1.5 "";}/*18px*/ 43 h2{font:normal 1.143em/1.5 "";}/*16px*/ 44 h3{font:600 1em/1.5 "";}/*14px*/ 45 .price{margin-left:5px;} 46 .price i{margin-left:2px; font-size:1.286em;} 47 .greyfont{color:#686868;} 48 .greyfont1{color:#909090;} 49 .bggrey{height:100%; background:#f5f5f5;} 50 51 /*header*/ 52 header{position:fixed; top:0; left:0; z-index:9999; width:100%; height:48px;background-color:#1491c5;} 53 .returnico{position:absolute; left:0; top:0; width:68px; height:48px; background-color:#15a4d5;} 54 .returnico:before{left:25px;top:16px;width:12px;height:20px; background-position:0 0;} 55 .icon_phone,.icon_home{width:42px;height:100%;top:0;position:relative;float:right;} 56 .icon_phone:before{width:11px;height:20px;top:16px;right:12px;background-position:-115px -65px;} 57 .icon_home:before{width:20px;height:19px;top:16px;right:10px;background-position:-83px -66px;} 58 header i:active{opacity:0.7; filter:alpha(opacity=70);} 59 header h1{position:absolute; width:100%;line-height:48px; text-align:center; letter-spacing:2px; color: #fff;} 60 .header_r,.header_rs{position:absolute;z-index:9; top:0; right:0; line-height:48px; padding:0 15px; font-size:18px; background:#15a4d5; color:#fff;} 61 .header_rs{padding:0 5px; font-size:12px; } 62 63 /*background-position*/ 64 .select_n:before{width:20px;height:20px;background-position:-18px 0;} 65 .select_n.current:before{background-position:-44px 0;} 66 67 /*searchbox*/ 68 .search_wrap{overflow:hidden; padding:10px; background:#dfeaf1;} 69 .search_box{position:relative; float:left; width:100%;} 70 .search_input{width:100%; padding:0 10px 0 28px; line-height:30px; background-color:#fff; border-radius:4px; color:#ccc;} 71 .fdj:before,.fdj:after,.search_box:before,.search_box:after{position:absolute; content:""; z-index:9;} 72 .fdj:before,.search_box:before{left:5px; top:7px; width:12px; height:12px; border:1px solid #bcbcbc; border-radius:12px;} 73 .fdj:after,.search_box:after{left:19px; top:17px; width:1px; height:8px; background:#bcbcbc;} 74 .search_cancel{ display:none;float:left; width:20%; line-height:30px; text-align:center; font-size:16px;color:#1491c5; background:none; border:none;} 75 .close_icon{display:none; position:absolute; z-index:10; top:8px; right:4px; width:16px; height:16px; border-radius:30px; background:#b1b1b1;} 76 .close_icon:before,.close_icon:after{position:absolute; content:""; top:4px; left:7px; width:2px; height:8px; background:#fff; } 77 .close_icon:before{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);} 78 .fdj:after,.search_box:after,.close_icon:after{-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg);} 79 .search_focus .search_box{width:80%;} 80 .search_focus .close_icon, .search_focus .search_cancel{display:block;} 81 .search_input:focus{color:#000;} 82 83 /*tab*/ 84 .tab{ background-color:#f8f8f8; border-bottom:1px solid #dfdfdf;} 85 .tab li{float:left; width:50%; height:39px; line-height:39px; text-align:center; border-right:1px solid #dfdfdf;} 86 .tab li:last-child{border-right:none;} 87 .tab li.tabcrt{ background-color:#dfdfdf;} 88 89 .tab_b{ background-color:#f5f5f5; border-bottom:1px solid #c1c1c1;} 90 .tab_b li{float:left; width:50%; height:39px; line-height:39px; text-align:center;} 91 .tab_b li:last-child{border-right:none;} 92 .tab_b li.tabcrt{color:#1491c5; border-bottom:4px solid #1491c5;} 93 94 /*list*/ 95 .list_st_border{ background:#fff; border-bottom:none; border:1px solid #cfcfcf; } 96 .list_st_border li{position:relative;padding:0 10px; line-height:42px; border-bottom:1px solid #cfcfcf;} 97 .list_st_border li:last-child{border-bottom:none;} 98 99 .list_sli{padding:10px; overflow:hidden; border-bottom:1px solid #cfcfcf; background:#fff;} 100 .list_sli .list_sunit{float:left;} 101 102 .citylist{color:#000;} 103 .citylist dt,.citylist dd{padding-left:10px;border-bottom:1px solid #e2e2e2;} 104 .citylist dt{line-height:25px; background-color:#eaeaea;} 105 .citylist dd{position:relative; font-size:16px; line-height:43px; background-color:#fff;} 106 .citylist .ok_crt{color:#1491c5;} 107 .citylist .ok_crt:after{position:absolute;content:""; right:10px; top:50%; margin-top:-6px; width:12px; height:13px; background-position:-110px 0;} 108 109 110 /*arr*/ 111 .li_arr_r{position:relative;} 112 .arr_r{position:absolute;right:0px; top:50%; width:30px; height:30px; margin-top:-15px; } 113 .arr_r:before,.arr_r:after,.li_arr_r:before,.li_arr_r:after{position: absolute; left:15px; content: "";width:2px; height:7px; background-color:#909090;} 114 .arr_r:before,.li_arr_r:before{top:10px;-webkit-transform:rotate(-45deg); -moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg);} 115 .arr_r:after,.li_arr_r:after{top:15px;-webkit-transform:rotate(45deg); -moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);} 116 .li_arr_r:before,.li_arr_r:after{left:auto; right:10px; top:50%; margin-top:-5px;} 117 .li_arr_r:after{margin-top:0;} 118 119 /*p*/ 120 .p_grey{margin:10px 5px; font-size:13px; color:#989898;} 121 .p_grey_center{ text-align:center; margin:20px 5px; font-size:13px; color:#989898;} 122 .p_hinttxt{padding:20px 10px; text-align:center; font-size:16px; color:#1491c5;} 123 124 125 /*btn*/ 126 .btn_yellow,.btn_del{width:100%; height:44px; line-height:42px; padding:0 10px; color:#fff;} 127 .btn_yellow{background:#ff9913;} 128 .btn_del{background:#ca4345;text-align:center;font-size:1.2em;} 129 130 .btn_pay{padding:0 20px;height:44px;float:right;background:#ff7d13;color:#fff;} 131 .btn_pay:active{background:#ff7300;} 132 .room_num {position:absolute; right:10px; width:100px; height:30px; line-height:30px;color:#000;background-color: #fff; text-align:center;border:#bfbfbf 1px solid;} 133 .room_num i{position:absolute; width:30px; height:30px; text-align:center; font:normal 2em/28px "Arial";} 134 .room_num i:first-child{left:0;background:#f4f4f4;color:#d9d9d9;font:normal 2.8em/25px "Arial";} 135 .room_num i:last-child{right:0;background:#06a2d0;color:#fff;} 136 137 138 /*日历*/ 139 .cui_cldwrap{color:#000;} 140 .cui_cldweek{height:25px; overflow:hidden;font:normal 12px/24px "verdana";border-bottom:1px solid #c8c8c8;} 141 .cui_cldweek li{float:left; width:14%; text-align:center; } 142 .cui_cldweek li:first-child,.cui_cldweek li:last-child{width:15%; color:#acacac;} 143 .cui_cldmonth{height:35px;text-align:center;font:normal 16px/35px "verdana"; background:#fff;} 144 .cui_cldunit{margin-bottom:20px;} 145 .cui_cld_daybox{overflow:hidden; background:#fff;} 146 .cui_cld_daybox li{float:left; width:14%; height:45px; padding:4px 0; font:normal 12px/45px "verdana"; overflow:hidden; text-align:center;} 147 .cui_cld_daybox li:nth-child(7n),.cui_cld_daybox li:nth-child(7n+1){width:15%;} 148 .cui_cld_daypass{ background:#f7f7f7;} 149 .cui_cld_daycrt{background:#06a2d0; color:#fff;} 150 .cui_cld_dayfuture{background:#fff;} 151 .cui_cld_day_nocrtmonth{ visibility:hidden;} 152 .cui_cld_day_havetxt em{display:block; line-height:25px;} 153 .cui_cld_day_havetxt i{display:block;line-height:15px;} 154 .cui_cld_day_hint{color:#06a2d0;} 155 /*全局XXXX*/ 156 157 /*弹出蓝色框*/ 158 .cui-pop-box{background:#fff;} 159 .cui-text-center{text-align:center;} 160 .cui-pop-box .cui-hd{height:40px;line-height:40px;font-size:1.2em;color:#fff;background:#1491c5;padding:0 10px;position:relative;} 161 .cui-pop-box .cui-hd .cui-close{position:absolute;top:10px; right:10px; width:18px; height:18px;line-height:18px;border-radius:50%; background:#fff;color:#1491c5;text-align:center;font-weight:bold;} 162 .cui-error{width:150px;margin:auto;border-radius:5px;background:rgba(73,73,73,1);padding:10px;color:#fff;font-weight:700;text-align:center;word-break:break-all;} 163 .cui-select-view li{border-bottom:#dfdfdf 1px solid;padding:.8em 2em .8em .8em;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;position:relative;} 164 .cui-select-view li.current{color:#1084bc;} 165 .cui-select-view li:active{background:rgba(0,0,0,.05);} 166 .cui-select-view li.current:before,.cui-select-view li.current:after{position:absolute;content:"";background:#1084bc;height:3px;top:50%;border-radius:3px;} 167 .cui-select-view li.current:before{width:18px;right:10px;margin-top:-2px;-webkit-transform:rotate(-50deg);-moz-transform:rotate(-50deg);-ms-transform:rotate(-50deg);transform:rotate(-50deg);} 168 .cui-select-view li.current:after{width:9px;right:22px;margin-top:2px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);} 169 170 .cui-roller{width:100%;height:90px;overflow:hidden;position:relative;display: -webkit-box;display: -moz-box;display: -ms-flexbox;display: -webkit-flex;display: flex;} 171 .cui-roller .ul-list{height:100%;text-align:center;font-size:1.1em;line-height:30px;-webkit-box-flex: 1;-moz-box-flex: 1;-webkit-flex: 1;-ms-flex: 1;flex: 1;} 172 .cui-mask{position:absolute;z-index:3;top: 0;left: 0;width: 100%;height: 100%;pointer-events: none; 173 background: linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%); 174 background: -webkit-gradient(linear,left bottom,left top,from(#fff),color-stop(0.52,rgba(245,245,245,0)),color-stop(0.48,rgba(245,245,245,0)),to(#fff)); 175 background: -webkit-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%); 176 background: -moz-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%); 177 } 178 .cui-lines{width:100%;height:34px;position:absolute;top:50%;margin-top:-17px;border-top:#dfdfdf 1px solid;border-bottom:#dfdfdf 1px solid;} 179 .cui-roller-tips{color:#8d8d8d;padding:5px;text-align:center;} 180 .cui-roller-btns{background:#f6f5f5;padding:10px;text-align:center;} 181 .cui-roller-btns span{width:45%;display:inline-block;padding:10px 0;color:#fff;} 182 .cui-roller-btns span:active{opacity:.75;} 183 .cui-roller-btns .cui-btns-cancel{background:#a9a9a9;margin-right:5%;} 184 .cui-roller-btns .cui-btns-sure{background:#ff9913;} 185 186 </style> 187 <style type="text/css"> 188 .c { position: absolute; top: 0; } 189 #y { left: 0; width: 30%; } 190 #m { left: 30%; right: 40%; } 191 #d { right: 0; width: 40%; } 192 </style> 193 <script src="../zepto.js" type="text/javascript"></script> 194 </head> 195 <body onselectstart="return false"> 196 <div class="cui-pop-box"> 197 <div class="cui-hd"> 198 <div class="cui-text-center"> 199 我是日历控件</div> 200 </div> 201 <div class="cui-bd"> 202 <div style="height: 90px; position: relative;"> 203 <div id="y" class="c"> 204 </div> 205 <div id="m" class="c"> 206 </div> 207 <div id="d" class="c"> 208 </div> 209 </div> 210 <p class="cui-roller-tips"> 211 点击获取日期吧!</p> 212 <div class="cui-roller-btns"> 213 <span class="cui-btns-cancel" id="set">取消</span> <span class="cui-btns-sure" id="get"> 214 获取日期</span> 215 </div> 216 </div> 217 </div> 218 219 <script type="text/javascript"> 220 221 // var myScroll = new iScroll('wl1'); 222 223 (function () { 224 //!!!由于动画原因,获取值可能会出现不准确的情况,比如正在动画却已经取值了 225 //所以设置了一个冷却时间,在冷却时间的情况下设置值等操作不能进行 226 //为了保证唯一性,全部使用index作为索引算了 227 var ScrollRadio = function (opts) { 228 opts = opts || {}; 229 //容器元素 230 this.wrapper = opts.wrapper || $(document); 231 var id = new Date().getTime() + Math.random() + 'id'; 232 this.body = [ 233 '<div class="cui-roller">', 234 '<ul class="ul-list" style=" position: absolute; width: 100%; z-index: 2; " id="' + id + '" >', 235 '</ul>', 236 '<div class="cui-mask"></div>', 237 '<div class="cui-lines"> </div>', 238 '</div>' 239 ].join(''); 240 this.body = $(this.body); 241 242 //真正拖动的元素(现在是ul) 243 this.dragEl = this.body.find('.ul-list'); 244 //数据源 245 this.data = opts.data || []; 246 this._changed = opts.changed || null; 247 //当前选项索引默认选择2项 248 this.selectedIndex = 1; 249 250 //当前选项值 251 // this.key = ''; 252 //当前选项显示的值 253 // this.value = ''; 254 255 /* 256 定位实际需要用到的信息 257 暂时不考虑水平移动吧 258 */ 259 this.itemHeight = 0; //单个item高度 260 this.dragHeight = 0; //拖动元素高度 261 this.dragTop = 0; //拖动元素top 262 this.animateParam = [10, 6, 2, 1, 0, 0, 0, 0, 0, 0, 0]; //动画参数 263 this.timeGap = 0; //时间间隔 264 this.touchTime = 0; //开始时间 265 this.moveAble = false; //是否正在移动 266 this.moveState = 'up'; //移动状态,up right down left 267 this.oTop = 0; //拖动前的top值 268 this.curTop = 0; //当前容器top 269 this.mouseY = 0; //鼠标第一次点下时相对父容器的位置 270 this.cooling = false; //是否处于冷却时间 271 272 this.init(); 273 }; 274 ScrollRadio.prototype = { 275 constructor: ScrollRadio, 276 init: function () { 277 this.initItem(); 278 this.wrapper.append(this.body); 279 this.initEventParam(); 280 this.bindEvent(); 281 }, 282 //增加数据 283 initItem: function () { 284 var _tmp, _data, i, k; 285 for (var i in this.data) { 286 _data = this.data[i] 287 _tmp = $('<li>' + (_data.val == undefined ? i : _data.val) + '</li>'); 288 _tmp.attr('data-index', i); 289 for (k in _data) { 290 _tmp.attr('data-' + k, _data[k]); 291 } 292 this.dragEl.append(_tmp); 293 } 294 }, 295 //初始化事件需要用到的参数信息 296 initEventParam: function () { 297 var offset = this.dragEl.offset(); 298 var itemOffset = this.dragEl.find('li').eq(0).offset(); 299 this.itemHeight = itemOffset.height 300 this.dragTop = offset.top; 301 this.dragHeight = this.dragEl[0].scrollHeight; 302 var s = ''; 303 }, 304 bindEvent: function () { 305 var scope = this; 306 this.dragEl[0].addEventListener("touchstart", function (e) { 307 scope.touchStart.call(scope, e); 308 }, false); 309 this.dragEl[0].addEventListener("touchend", function (e) { 310 scope.touchEnd.call(scope, e); 311 }, false); 312 this.dragEl[0].addEventListener("touchmove", function (e) { 313 scope.touchMove.call(scope, e); 314 }, false); 315 }, 316 touchStart: function (e) { 317 if (this.cooling) return false; //冷却时间不能开始 318 319 //需要判断是否是拉取元素,此处需要递归验证,这里暂时不管 320 //!!!!!!!!此处不严谨 321 var el = $(e.srcElement).parent(), pos; 322 if (el.hasClass('ul-list')) { 323 this.moveAble = true; 324 325 this.touchTime = e.timeStamp; 326 //获取鼠标信息 327 pos = this.getMousePos(e.changedTouches[0]); 328 //注意,此处是相对位置,注意该处还与动画有关,所以高度必须动态计算 329 //可以设置一个冷却时间参数,但想想还是算了 330 //最后还是使用了冷却时间 331 // var top = parseFloat(this.dragEl.css('top')) || 0; 332 // this.mouseY = pos.top - top; 333 this.mouseY = pos.top - this.curTop; 334 this.moveAble = true; 335 } 336 }, 337 touchMove: function (e) { 338 if (!this.moveAble) return false; 339 var pos = this.getMousePos(e.changedTouches[0]); 340 //先获取相对容器的位置,在将两个鼠标位置相减 341 this.curTop = pos.top - this.mouseY; 342 this.dragEl.css('top', this.curTop + 'px'); 343 e.preventDefault(); 344 }, 345 touchEnd: function (e) { 346 if (!this.moveAble) return false; 347 this.cooling = true; //开启冷却时间 348 349 //时间间隔 350 var scope = this; 351 this.timeGap = e.timeStamp - this.touchTime; 352 var flag = this.oTop <= this.curTop ? 1 : -1; //判断是向上还是向下滚动 353 var flag2 = this.curTop > 0 ? 1 : -1; //这个会影响后面的计算结果 354 this.moveState = flag > 0 ? 'up' : 'down'; 355 var ih = parseFloat(this.itemHeight); 356 var ih1 = ih / 2; 357 358 var top = Math.abs(this.curTop); 359 var mod = top % ih; 360 top = (parseInt(top / ih) * ih + (mod > ih1 ? ih : 0)) * flag2; 361 362 var step = parseInt(this.timeGap / 50); 363 step = step > 0 ? step : 0; 364 var speed = this.animateParam[step] || 0; 365 var increment = speed * ih * flag 366 top += increment; 367 //!!!此处动画可能导致数据不同步,后期改造需要加入冷却时间 368 if (this.oTop != this.curTop) { 369 this.dragEl.animate({ 370 top: top + 'px' 371 }, 100 + (speed * 20), 'ease-out', function () { 372 var _top = top, t = false; ; 373 if (top > ih) { 374 _top = ih; 375 t = true; 376 } 377 if (top < 0 && (top + scope.dragHeight < ih * 2)) { 378 t = true; 379 _top = (scope.dragHeight - ih * 2) * (-1); 380 } 381 if (t) { 382 scope.dragEl.animate({ 383 top: _top + 'px' 384 }, 10, 'ease-in-out', function () { 385 scope.oTop = _top; 386 scope.curTop = _top; 387 scope.cooling = false; //关闭冷却时间 388 scope.onTouchEnd(); 389 }); 390 } else { 391 scope.cooling = false; //关闭冷却时间 392 scope.oTop = top; 393 scope.curTop = top; 394 scope.onTouchEnd(); 395 } 396 }); 397 } else { 398 this.cooling = false; //关闭冷却时间 399 this.onTouchEnd(); 400 } 401 this.moveAble = false; 402 }, 403 onTouchEnd: function () { 404 var i = parseInt((this.curTop - this.itemHeight) / parseFloat(this.itemHeight)); 405 this.selectedIndex = Math.abs(i); 406 var secItem = this.data[this.selectedIndex]; 407 //触发变化事件 408 var changed = this._changed; 409 if (changed && typeof changed == 'function') { 410 changed.call(this, secItem); 411 } 412 console.log(this.selectedIndex, secItem); 413 }, 414 setKey: function (k) { }, 415 setVal: function (v) { }, 416 setIndex: function (i) { 417 var i = parseInt(i); 418 if (i >= this.data.length || i < 0) return false; 419 420 this.selectedIndex = i; 421 this.curTop = (i * this.itemHeight * (-1) + this.itemHeight); 422 this.dragEl.css('top', this.curTop + 'px'); 423 }, 424 getSelected: function () { 425 return this.data[this.selectedIndex]; 426 }, 427 getByKey: function (k) { }, 428 getByVal: function (v) { }, 429 getByIndex: function (i) { }, 430 //获取鼠标信息 431 getMousePos: function (event) { 432 var top, left; 433 top = Math.max(document.body.scrollTop, document.documentElement.scrollTop); 434 left = Math.max(document.body.scrollLeft, document.documentElement.scrollLeft); 435 return { 436 top: top + event.clientY, 437 left: left + event.clientX 438 }; 439 } 440 }; 441 window.ScrollRadio = ScrollRadio; 442 443 })(); 444 445 var yy = []; 446 for (var i = 0; i < 150; i++) { 447 var temp = { val: 1900 + i }; 448 yy.push(temp); 449 } 450 451 var mm = []; 452 for (var i = 0; i < 12; i++) { 453 var temp = { val: i > 10 ? i : (0 + '' + i) }; 454 mm.push(temp); 455 } 456 457 var dd = []; 458 for (var i = 0; i < 31; i++) { 459 var temp = { val: i > 10 ? i : (0 + '' + i) }; 460 dd.push(temp); 461 } 462 463 var y = new ScrollRadio({ 464 wrapper: $('#y'), 465 data: yy 466 }); 467 var m = new ScrollRadio({ 468 wrapper: $('#m'), 469 data: mm 470 }); 471 var d = new ScrollRadio({ 472 wrapper: $('#d'), 473 data: dd 474 }); 475 476 $('#get').click(function () { 477 alert(y.getSelected().val + '-' + m.getSelected().val + '-' + d.getSelected().val); 478 }); 479 480 var s = ''; 481 482 </script> 483 </body> 484 </html>
今天时间用多了,老夫有点来不起了,我们下次再完善吧。。。。。。
结语
若是各位觉得有用的话不妨用一用,发现什么BUG请留言,我下次一并更新,BUG应该很多的。