前言
小伙伴们好,很久不见了。最近工作进入正常期了,所以慢慢的悠闲的时间久没有了,所以不能每天水一篇了。
最近也在听师傅(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应该很多的。
来源:https://www.cnblogs.com/yexiaochai/p/3322477.html
