zoukankan      html  css  js  c++  java
  • 日历插件(beta)

    仿iphone日历插件(beta)

    前言

    小伙伴们好,很久不见了。最近工作进入正常期了,所以慢慢的悠闲的时间久没有了,所以不能每天水一篇了。

    最近也在听师傅(http://home.cnblogs.com/u/aaronjs/)的教导开始阅读jquery源码了,怎么说呢,阅读的效果其实不是太好。

    一来是时间断断续续的没有接上,今天读完明天又忘了,到第三天再读的话,就很多都忘记了;

    二来是jquery其实还是有一定难度,加之篇幅也很长,所以读起来还是有一点吃力(我甚至有时候有种想睡的感觉),过了2星期才陆陆续续把core读完,结果很多都无法理解,再加油吧。

    反正今年的目标就是把jquery读懂,时间多,不着急了。

    时间比较紧未做兼容处理,请使用手机/或者使用chrome开启touch功能查看,后期补上兼容方案,以及修复BUG

    关于工作

    最近工作上需要在我们的网页上加入一些动画:

    ① 页面的切入切出的转场动画

    ② 模仿一个iphone的日历控件

    转场动画做的时候其实碰到了很多坑,而且最后做出的效果也一般,因为既有的框架与dom结构已经出来了好久了,改不得,而且就算改了效果也不能保证好,所以暂时放下

    这里说的仿iphone日历控件,不如说模仿一个单选框来的实在,而且我这里说是插件,完全就算标题党了,各位可以忽视,所以今日正题吧。

    iphone的感觉

    第一步我们要找到iphone的感觉,那么iphone是个什么感觉呢:

    大概是这么个感觉,但是我做出来却变成了这种感觉,将就着看吧:

    总体思路

    PS:现在其实正在写功能代码,所以,现在我们是边写边做的,思路乱了各位请包涵

    测试代码

    这个代码很烂,各位就不要看了,我都不知道怎么写出来的,后面点整理吧,里面的CSS不想写就直接拿别人的用了

     View Code

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title></title>
    <style type="text/css">

    /*reset*/
    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}
    body,button,input,select,textarea{font:normal 14px/1.5 Tahoma,"Lucida Grande",Verdana,"Microsoft YaHei",hei;}
    article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section,iframe{display:block;}
    h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:500;}
    address,cite,dfn,em,var,i{font-style:normal;font-weight:normal;font-family:arial;}
    ul,ol{list-style:none}
    a{color:#000;text-decoration:none}
    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;}
    fieldset,img,button,input{border:0}
    button,input,select,textarea{font-size:100%}
    table{border-collapse:collapse;border-spacing:0}
    input[type="button"],input[type="submit"]{-webkit-appearance:none;}
    body{min-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;}
    html,body,.h100{ height:100%; }
    dfn{color:#ff9913; font-size:12px; font-weight:normal;}
    /*-----------------------------------------common--------------------*/
    .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;}
    .i_bef:before,.i_aft:after,.carlist li:before{position: absolute;content: "";}
    .abs_size{-moz-box-sizing:border-box; -webkit-box-sizing:border-box; box-sizing:border-box;}
    .opacity{opacity:0.7; filter:alpha(opacity=70);}

    /*active*/
    .list_st_border li:active,.p_hinttxt:active,.search_cancel:active,.citylist dd:active{ background:#f8f8f8;}
    .btn_yellow:active{background:#eb840f;}

    /*layout*/
    .wrap{margin-top:48px;}
    .wrap_pb{margin-top:48px; padding-bottom:45px;}
    .p10{padding:10px;}
    .hm{text-align:center;}
    .break_all{word-break:break-all;}
    .fix_b{position:fixed; bottom:0; left:0;z-index:9999;}

    /*font bg color size*/
    h1{font:normal 1.286em/1.5 "";}/*18px*/
    h2{font:normal 1.143em/1.5 "";}/*16px*/
    h3{font:600 1em/1.5 "";}/*14px*/
    .price{margin-left:5px;}
    .price i{margin-left:2px; font-size:1.286em;}
    .greyfont{color:#686868;}
    .greyfont1{color:#909090;}
    .bggrey{height:100%; background:#f5f5f5;}

    /*header*/
    header{position:fixed; top:0; left:0; z-index:9999; 100%; height:48px;background-color:#1491c5;}
    .returnico{position:absolute; left:0; top:0; 68px; height:48px; background-color:#15a4d5;}
    .returnico:before{left:25px;top:16px;12px;height:20px; background-position:0 0;}
    .icon_phone,.icon_home{42px;height:100%;top:0;position:relative;float:right;}
    .icon_phone:before{11px;height:20px;top:16px;right:12px;background-position:-115px -65px;}
    .icon_home:before{20px;height:19px;top:16px;right:10px;background-position:-83px -66px;}
    header i:active{opacity:0.7; filter:alpha(opacity=70);}
    header h1{position:absolute; 100%;line-height:48px; text-align:center; letter-spacing:2px; color: #fff;}
    .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;}
    .header_rs{padding:0 5px; font-size:12px; }

    /*background-position*/
    .select_n:before{20px;height:20px;background-position:-18px 0;}
    .select_n.current:before{background-position:-44px 0;}

    /*searchbox*/
    .search_wrap{overflow:hidden; padding:10px; background:#dfeaf1;}
    .search_box{position:relative; float:left; 100%;}
    .search_input{100%; padding:0 10px 0 28px; line-height:30px; background-color:#fff; border-radius:4px; color:#ccc;}
    .fdj:before,.fdj:after,.search_box:before,.search_box:after{position:absolute; content:""; z-index:9;}
    .fdj:before,.search_box:before{left:5px; top:7px; 12px; height:12px; border:1px solid #bcbcbc; border-radius:12px;}
    .fdj:after,.search_box:after{left:19px; top:17px; 1px; height:8px; background:#bcbcbc;}
    .search_cancel{ display:none;float:left; 20%; line-height:30px; text-align:center; font-size:16px;color:#1491c5; background:none; border:none;}
    .close_icon{display:none; position:absolute; z-index:10; top:8px; right:4px; 16px; height:16px; border-radius:30px; background:#b1b1b1;}
    .close_icon:before,.close_icon:after{position:absolute; content:""; top:4px; left:7px; 2px; height:8px; background:#fff; }
    .close_icon:before{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);}
    .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);}
    .search_focus .search_box{80%;}
    .search_focus .close_icon, .search_focus .search_cancel{display:block;}
    .search_input:focus{color:#000;}

    /*tab*/
    .tab{ background-color:#f8f8f8; border-bottom:1px solid #dfdfdf;}
    .tab li{float:left; 50%; height:39px; line-height:39px; text-align:center; border-right:1px solid #dfdfdf;}
    .tab li:last-child{border-right:none;}
    .tab li.tabcrt{ background-color:#dfdfdf;}

    .tab_b{ background-color:#f5f5f5; border-bottom:1px solid #c1c1c1;}
    .tab_b li{float:left; 50%; height:39px; line-height:39px; text-align:center;}
    .tab_b li:last-child{border-right:none;}
    .tab_b li.tabcrt{color:#1491c5; border-bottom:4px solid #1491c5;}

    /*list*/
    .list_st_border{ background:#fff; border-bottom:none; border:1px solid #cfcfcf; }
    .list_st_border li{position:relative;padding:0 10px; line-height:42px; border-bottom:1px solid #cfcfcf;}
    .list_st_border li:last-child{border-bottom:none;}

    .list_sli{padding:10px; overflow:hidden; border-bottom:1px solid #cfcfcf; background:#fff;}
    .list_sli .list_sunit{float:left;}

    .citylist{color:#000;}
    .citylist dt,.citylist dd{padding-left:10px;border-bottom:1px solid #e2e2e2;}
    .citylist dt{line-height:25px; background-color:#eaeaea;}
    .citylist dd{position:relative; font-size:16px; line-height:43px; background-color:#fff;}
    .citylist .ok_crt{color:#1491c5;}
    .citylist .ok_crt:after{position:absolute;content:""; right:10px; top:50%; margin-top:-6px; 12px; height:13px; background-position:-110px 0;}


    /*arr*/
    .li_arr_r{position:relative;}
    .arr_r{position:absolute;right:0px; top:50%; 30px; height:30px; margin-top:-15px; }
    .arr_r:before,.arr_r:after,.li_arr_r:before,.li_arr_r:after{position: absolute; left:15px; content: "";2px; height:7px; background-color:#909090;}
    .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);}
    .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);}
    .li_arr_r:before,.li_arr_r:after{left:auto; right:10px; top:50%; margin-top:-5px;}
    .li_arr_r:after{margin-top:0;}

    /*p*/
    .p_grey{margin:10px 5px; font-size:13px; color:#989898;}
    .p_grey_center{ text-align:center; margin:20px 5px; font-size:13px; color:#989898;}
    .p_hinttxt{padding:20px 10px; text-align:center; font-size:16px; color:#1491c5;}


    /*btn*/
    .btn_yellow,.btn_del{100%; height:44px; line-height:42px; padding:0 10px; color:#fff;}
    .btn_yellow{background:#ff9913;}
    .btn_del{background:#ca4345;text-align:center;font-size:1.2em;}

    .btn_pay{padding:0 20px;height:44px;float:right;background:#ff7d13;color:#fff;}
    .btn_pay:active{background:#ff7300;}
    .room_num {position:absolute; right:10px; 100px; height:30px; line-height:30px;color:#000;background-color: #fff; text-align:center;border:#bfbfbf 1px solid;}
    .room_num i{position:absolute; 30px; height:30px; text-align:center; font:normal 2em/28px "Arial";}
    .room_num i:first-child{left:0;background:#f4f4f4;color:#d9d9d9;font:normal 2.8em/25px "Arial";}
    .room_num i:last-child{right:0;background:#06a2d0;color:#fff;}


    /*日历*/
    .cui_cldwrap{color:#000;}
    .cui_cldweek{height:25px; overflow:hidden;font:normal 12px/24px "verdana";border-bottom:1px solid #c8c8c8;}
    .cui_cldweek li{float:left; 14%; text-align:center; }
    .cui_cldweek li:first-child,.cui_cldweek li:last-child{15%; color:#acacac;}
    .cui_cldmonth{height:35px;text-align:center;font:normal 16px/35px "verdana"; background:#fff;}
    .cui_cldunit{margin-bottom:20px;}
    .cui_cld_daybox{overflow:hidden; background:#fff;}
    .cui_cld_daybox li{float:left; 14%; height:45px; padding:4px 0; font:normal 12px/45px "verdana"; overflow:hidden; text-align:center;}
    .cui_cld_daybox li:nth-child(7n),.cui_cld_daybox li:nth-child(7n+1){15%;}
    .cui_cld_daypass{ background:#f7f7f7;}
    .cui_cld_daycrt{background:#06a2d0; color:#fff;}
    .cui_cld_dayfuture{background:#fff;}
    .cui_cld_day_nocrtmonth{ visibility:hidden;}
    .cui_cld_day_havetxt em{display:block; line-height:25px;}
    .cui_cld_day_havetxt i{display:block;line-height:15px;}
    .cui_cld_day_hint{color:#06a2d0;}
    /*全局XXXX*/

    /*弹出蓝色框*/
    .cui-pop-box{background:#fff;}
    .cui-text-center{text-align:center;}
    .cui-pop-box .cui-hd{height:40px;line-height:40px;font-size:1.2em;color:#fff;background:#1491c5;padding:0 10px;position:relative;}
    .cui-pop-box .cui-hd .cui-close{position:absolute;top:10px; right:10px; 18px; height:18px;line-height:18px;border-radius:50%; background:#fff;color:#1491c5;text-align:center;font-weight:bold;}
    .cui-error{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;}
    .cui-select-view li{border-bottom:#dfdfdf 1px solid;padding:.8em 2em .8em .8em;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;position:relative;}
    .cui-select-view li.current{color:#1084bc;}
    .cui-select-view li:active{background:rgba(0,0,0,.05);}
    .cui-select-view li.current:before,.cui-select-view li.current:after{position:absolute;content:"";background:#1084bc;height:3px;top:50%;border-radius:3px;}
    .cui-select-view li.current:before{18px;right:10px;margin-top:-2px;-webkit-transform:rotate(-50deg);-moz-transform:rotate(-50deg);-ms-transform:rotate(-50deg);transform:rotate(-50deg);}
    .cui-select-view li.current:after{9px;right:22px;margin-top:2px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);}

    .cui-roller{100%;height:90px;overflow:hidden;position:relative;display: -webkit-box;display: -moz-box;display: -ms-flexbox;display: -webkit-flex;display: flex;}
    .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;}
    .cui-mask{position:absolute;z-index:3;top: 0;left: 0; 100%;height: 100%;pointer-events: none;
    background: linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%);
    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));
    background: -webkit-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%);
    background: -moz-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%);
    }
    .cui-lines{100%;height:34px;position:absolute;top:50%;margin-top:-17px;border-top:#dfdfdf 1px solid;border-bottom:#dfdfdf 1px solid;}
    .cui-roller-tips{color:#8d8d8d;padding:5px;text-align:center;}
    .cui-roller-btns{background:#f6f5f5;padding:10px;text-align:center;}
    .cui-roller-btns span{45%;display:inline-block;padding:10px 0;color:#fff;}
    .cui-roller-btns span:active{opacity:.75;}
    .cui-roller-btns .cui-btns-cancel{background:#a9a9a9;margin-right:5%;}
    .cui-roller-btns .cui-btns-sure{background:#ff9913;}

    </style>
    <script src="../zepto.js" type="text/javascript"></script>
    </head>

    <body id="ctripPage" onselectstart="return false">

    <!--滚轮-->
    <div class="cui-pop-box">
    <div class="cui-hd"><div class="cui-text-center">滚轮滚轮滚轮</div></div>
    <div class="cui-bd">
    <div class="cui-roller">
    <ul class="ul-list" style=" position: absolute; 100%; z-index: 2; " >
    <li>选项1</li>
    <li>选项2</li>
    <li>选项3</li>
    <li>选项4</li>
    <li>选项5</li>
    <li>选项6</li>
    <li>选项7</li>
    <li>选项8</li>
    <li>选项9</li>
    <li>选项10</li>
    <li>选项11</li>
    <li>选项12</li>
    <li>选项13</li>
    <li>选项14</li>
    <li>选项15</li>
    <li>选项16</li>
    <li>选项17</li>
    <li>选项18</li>
    <li>选项19</li>
    <li>选项20</li> <li>选项1</li>
    <li>选项2</li>
    <li>选项3</li>
    <li>选项4</li>
    <li>选项5</li>
    <li>选项6</li>
    <li>选项7</li>
    <li>选项8</li>
    <li>选项9</li>
    <li>选项10</li>
    <li>选项11</li>
    <li>选项12</li>
    <li>选项13</li>
    <li>选项14</li>
    <li>选项15</li>
    <li>选项16</li>
    <li>选项17</li>
    <li>选项18</li>
    <li>选项19</li>
    <li>选项20</li>
    </ul>

    <div class="cui-mask" style=""></div>
    <div class="cui-lines">&nbsp;</div>
    </div>
    <p class="cui-roller-tips">提示信息</p>
    <div class="cui-roller-btns">
    <span class="cui-btns-cancel">取消</span><span class="cui-btns-sure">确定</span>
    </div>
    </div>
    </div>

    <script type="text/javascript">

    // var myScroll = new iScroll('wl1');


    var y1 = 0, y2 = 0;
    var moveAble = false;
    var dragEl = null;
    var parent = $('.cui-roller');
    var offset;
    var el_top = 0;
    var o_top = 0;
    var t1 = 0, t2 = 0;
    var timer = null;

    document.addEventListener("touchstart", touchStart, false);
    document.addEventListener("touchend", touchEnd, false);
    document.addEventListener("touchmove", touchMove, false);

    function touchStart(e) {
    t1 = e.timeStamp;
    var srcElement = $(e.srcElement), pos;
    dragEl = $(e.srcElement).parent();
    if (dragEl.hasClass('ul-list')) {
    var pos = getMousePos(e.changedTouches[0]);

    offset = dragEl.offset();
    y1 = pos.top - offset.top;
    var top = parseFloat(dragEl.css('top')) || 0;
    o_top = top;
    y1 = y1 - parseFloat(top);
    moveAble = true;
    }
    }

    function touchMove(e) {
    if (!dragEl || !moveAble) return false;
    var pos = getMousePos(e.changedTouches[0]);
    y2 = pos.top - y1 - offset.top;

    if (timer) clearTimeout(timer);


    el_top = y2;
    dragEl.css('top', y2 + 'px');
    e.preventDefault();
    }


    function touchEnd(e) {
    t2 = e.timeStamp - t1;
    var flag = o_top <= el_top ? 1 : -1;
    var flag2 = el_top > 0 ? 1 : -1;

    el_top = Math.abs(el_top);
    var mod = el_top % 30;
    el_top = (parseInt(el_top / 30) * 30 + (mod > 15 ? 30 : 0)) * flag2;
    if (t2 >= 200) {
    dragEl.animate({
    top: el_top + 'px'
    }, 100, 'ease-in-out', function () {
    if (el_top > 30) {
    dragEl.animate({
    top: '30px'
    }, 10, 'ease-in-out');
    }
    if (el_top < 0 && (el_top + dragEl[0].scrollHeight < 60)) {
    dragEl.animate({
    top: '-' + (dragEl[0].scrollHeight - 60) + 'px'
    }, 10, 'ease-in-out');
    }
    });
    } else {
    var step = parseInt(t2 / 50);
    console.log(t2, step);

    var param = [10, 6, 4, 2];
    var _tmp = param[step] * 30 * flag;
    _tmp = el_top + _tmp;
    dragEl.animate({
    top: (_tmp) + 'px'
    }, 100 + (param[step] * 50), 'ease-in-out', function () {
    if (_tmp > 30) {
    dragEl.animate({
    top: '30px'
    }, 10, 'ease-in-out');
    }
    if (_tmp < 0 && (_tmp + dragEl[0].scrollHeight < 60)) {
    dragEl.animate({
    top: '-' + (dragEl[0].scrollHeight - 60) + 'px'
    }, 10, 'ease-in-out');
    }
    });


    }
    moveAble = false;
    }

    function getMousePos(event) {
    var top, left;
    top = Math.max(document.body.scrollTop, document.documentElement.scrollTop);
    left = Math.max(document.body.scrollLeft, document.documentElement.scrollLeft);
    return {
    top: top + event.clientY,
    left: left + event.clientX
    };
    };

    var s = '';

    </script>

    </body>
    </html>

    demo请按照图示观看

    http://sandbox.runjs.cn/show/dkf9dkwq

    关于iscroll

    最开始我们总是喜欢找一些已经存在了的解决方案来试试,这样就比较简单了,但是iscroll有一定问题就是他太大了。

    最简单的压缩了都快10k了,所以直接给毙了,这里暂时就用不到他了。

    zepto的touch事件

    我是一个喜欢偷懒的人,我看着zepto有touch事件,本来想拿来直接用用谁知道。。。

     View Code

    // Zepto.js
    // (c) 2010-2012 Thomas Fuchs
    // Zepto.js may be freely distributed under the MIT license.

    ;(function($){
    var touch = {},
    touchTimeout, tapTimeout, swipeTimeout,
    longTapDelay = 750, longTapTimeout

    function parentIfText(node) {
    return 'tagName' in node ? node : node.parentNode
    }

    function swipeDirection(x1, x2, y1, y2) {
    var xDelta = Math.abs(x1 - x2), yDelta = Math.abs(y1 - y2)
    return xDelta >= yDelta ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
    }

    function longTap() {
    longTapTimeout = null
    if (touch.last) {
    touch.el.trigger('longTap')
    touch = {}
    }
    }

    function cancelLongTap() {
    if (longTapTimeout) clearTimeout(longTapTimeout)
    longTapTimeout = null
    }

    function cancelAll() {
    if (touchTimeout) clearTimeout(touchTimeout)
    if (tapTimeout) clearTimeout(tapTimeout)
    if (swipeTimeout) clearTimeout(swipeTimeout)
    if (longTapTimeout) clearTimeout(longTapTimeout)
    touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null
    touch = {}
    }

    $(document).ready(function(){
    var now, delta

    $(document.body)
    .bind('touchstart', function(e){
    now = Date.now()
    delta = now - (touch.last || now)
    touch.el = $(parentIfText(e.touches[0].target))
    touchTimeout && clearTimeout(touchTimeout)
    touch.x1 = e.touches[0].pageX
    touch.y1 = e.touches[0].pageY
    if (delta > 0 && delta <= 250) touch.isDoubleTap = true
    touch.last = now
    longTapTimeout = setTimeout(longTap, longTapDelay)
    })
    .bind('touchmove', function(e){
    cancelLongTap()
    touch.x2 = e.touches[0].pageX
    touch.y2 = e.touches[0].pageY
    if (Math.abs(touch.x1 - touch.x2) > 10)
    e.preventDefault()
    })
    .bind('touchend', function(e){
    cancelLongTap()

    // swipe
    if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) ||
    (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30))

    swipeTimeout = setTimeout(function() {
    touch.el.trigger('swipe')
    touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)))
    touch = {}
    }, 0)

    // normal tap
    else if ('last' in touch)

    // delay by one tick so we can cancel the 'tap' event if 'scroll' fires
    // ('tap' fires before 'scroll')
    tapTimeout = setTimeout(function() {

    // trigger universal 'tap' with the option to cancelTouch()
    // (cancelTouch cancels processing of single vs double taps for faster 'tap' response)
    var event = $.Event('tap')
    event.cancelTouch = cancelAll
    touch.el.trigger(event)

    // trigger double tap immediately
    if (touch.isDoubleTap) {
    touch.el.trigger('doubleTap')
    touch = {}
    }

    // trigger single tap after 250ms of inactivity
    else {
    touchTimeout = setTimeout(function(){
    touchTimeout = null
    touch.el.trigger('singleTap')
    touch = {}
    }, 250)
    }

    }, 0)

    })
    .bind('touchcancel', cancelAll)

    $(window).bind('scroll', cancelAll)
    })

    ;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(m){
    $.fn[m] = function(callback){ return this.bind(m, callback) }
    })
    })(Zepto)

    这个就是zepto的touch事件,可以看到他只是对touchend有所监控,会触发一点点事件,所以和我们没有一毛钱关系

    在此我便认命的自己敲下了以下代码:

    1 document.addEventListener("touchstart", touchStart, false);
    2 document.addEventListener("touchend", touchEnd, false);
    3 document.addEventListener("touchmove", touchMove, false);

    鼠标拖动

    该功能的第一个技术点,便是元素跟着鼠标移动,拖到哪里就是哪里,这个大家都比较熟悉了,就不多说

    touchend

    当拖动结束时,我们要做很多后续的工作:

    ① 让选项进入既定的轨道

    ② 是否具有动画效果

    ③ 动画效果的步长等

    PS:开始觉得有几个点可以说说,结果真的写出来却无话可说了,哎。。。。。。

    经过以上版本,我们的粗制滥造版便出现了,就是以上的代码。

    封装

    于是我们就可以在这个基础上整理代码,封装起来了,请看下一步。

    整理封装

    首先,我们虽然写的不是插件,但是还是应该让他有插件的样子,来点简单的修饰吧。

    经过一阶段的休整,我们的代码成了这个样子了:

     View Code

    (function () {
    var ScrollRadio = function (opts) {
    opts = opts || {};
    //容器元素
    this.wrapper = opts.wrapper || $(document);
    this.body = [
    '<div class="cui-roller">',
    '<ul class="ul-list" style=" position: absolute; 100%; z-index: 2; " >',
    '</ul>',
    '<div class="cui-mask"></div>',
    '<div class="cui-lines">&nbsp;</div>',
    '</div>'
    ].join('');
    this.body = $(this.body);

    //真正拖动的元素(现在是ul)
    this.dragEl = this.body.find('.ul-list');
    //数据源
    this.data = opts.data || [];
    this._changed = opts.changed || null;
    //当前选项索引
    this.selectedIndex = 0;
    //当前选项值
    this.key = '';
    //当前选项显示的值
    this.value = '';

    /*
    定位实际需要用到的信息
    暂时不考虑水平移动吧
    */
    this.itemHeight = 0; //单个item高度
    this.dragHeight = 0; //拖动元素高度
    this.dragTop = 0; //拖动元素top
    this.animateParam = [10, 8, 7, 6, 6, 6, 5, 5, 4, 2, 0]; //动画参数
    this.timeGap = 0; //时间间隔
    this.touchTime = 0; //开始时间
    this.moveAble = false; //是否正在移动
    this.moveState = 'up'; //移动状态,up right down left
    this.oTop = 0; //拖动前的top值
    this.curTop = 0; //当前容器top
    this.mouseY = 0; //鼠标第一次点下时相对父容器的位置


    this.init();
    };
    ScrollRadio.prototype = {
    constructor: ScrollRadio,
    init: function () {
    this.initItem();
    this.wrapper.append(this.body);
    this.initEventParam();
    this.bindEvent();

    return this;
    },
    //增加数据
    initItem: function () {
    var _tmp, _data, i, k;
    for (var i in this.data) {
    _data = this.data[i]
    _tmp = $('<li>' + (_data.val == undefined ? i : _data.val) + '</li>');
    _tmp.attr('data-index', i);
    for (k in _data) {
    _tmp.attr('data-' + k, _data[k]);
    }
    this.dragEl.append(_tmp);
    }
    },
    //初始化事件需要用到的参数信息
    initEventParam: function () {
    var offset = this.dragEl.offset();
    var itemOffset = this.dragEl.find('li').eq(0).offset();
    this.itemHeight = itemOffset.height
    this.dragTop = offset.top;
    this.dragHeight = this.dragEl[0].scrollHeight;
    var s = '';
    },
    bindEvent: function () {
    var scope = this;
    document.addEventListener("touchstart", function (e) {
    scope.touchStart.call(scope, e);
    }, false);
    document.addEventListener("touchend", function (e) {
    scope.touchEnd.call(scope, e);
    }, false);
    document.addEventListener("touchmove", function (e) {
    scope.touchMove.call(scope, e);
    }, false);
    },
    touchStart: function (e) {
    //需要判断是否是拉取元素,此处需要递归验证,这里暂时不管
    //!!!!!!!!此处不严谨
    var el = $(e.srcElement).parent(), pos;
    if (el.hasClass('ul-list')) {
    this.touchTime = e.timeStamp;
    //获取鼠标信息
    pos = this.getMousePos(e.changedTouches[0]);
    //注意,此处是相对位置
    this.mouseY = pos.top - this.curTop;
    this.moveAble = true;
    }
    },
    touchMove: function (e) {
    if (!this.moveAble) return false;
    var pos = this.getMousePos(e.changedTouches[0]);
    //先获取相对容器的位置,在将两个鼠标位置相减
    this.curTop = pos.top - this.mouseY;

    this.dragEl.css('top', this.curTop + 'px');


    e.preventDefault();
    },
    touchEnd: function (e) {
    //时间间隔
    var scope = this;
    this.timeGap = e.timeStamp - this.touchTime;
    var flag = this.oTop <= this.curTop ? 1 : -1; //判断是向上还是向下滚动
    var flag2 = this.curTop > 0 ? 1 : -1; //这个会影响后面的计算结果
    this.moveState = flag > 0 ? 'up' : 'down';
    var ih = parseFloat(this.itemHeight);
    var ih1 = ih / 2;

    var top = Math.abs(this.curTop);
    var mod = top % ih;
    top = (parseInt(top / ih) * ih + (mod > ih1 ? ih : 0)) * flag2;

    var step = parseInt(this.timeGap / 10 - 10);
    step = step > 0 ? step : 0;
    var speed = this.animateParam[step] || 0;
    var increment = speed * ih * flag
    top += increment;
    this.dragEl.animate({
    top: top + 'px'
    }, 100 + (speed * 20), 'ease-in-out', function () {
    if (top > ih) {
    scope.dragEl.animate({
    top: ih + 'px'
    }, 10, 'ease-in-out');
    }
    if (top < 0 && (top + scope.dragHeight < ih * 2)) {
    scope.dragEl.animate({
    top: '-' + (scope.dragHeight - ih * 2) + 'px'
    }, 10, 'ease-in-out');
    }
    });

    console.log(this.timeGap, top, increment);

    this.oTop = top;
    this.curTop = top;
    this.moveAble = false;

    },
    setKey: function (k) {

    },
    setVal: function (v) { },
    setIndex: function (i) {

    },
    getSelected: function () {

    },
    getByKey: function (k) { },
    getByVal: function (v) { },
    getByIndex: function (i) { },

    //选项改变时候触发
    changed: function () {

    },
    //获取鼠标信息
    getMousePos: function (event) {
    var top, left;
    top = Math.max(document.body.scrollTop, document.documentElement.scrollTop);
    left = Math.max(document.body.scrollLeft, document.documentElement.scrollLeft);
    return {
    top: top + event.clientY,
    left: left + event.clientX
    };
    }

    };


    window.ScrollRadio = ScrollRadio;

    })();

    var data = [];
    for (var i = 0; i < 100; i++) {
    var temp = { val: '选项-' + i };
    data.push(temp);
    }

    var myScroll = new ScrollRadio({
    wrapper: $('#ctripPage'),
    data: data
    });


    var s = '';

    http://sandbox.runjs.cn/show/biousc1u

    其中动画步长可以自己调节,选一个自己认为合适的,下面接着更新。

    设置/获取

     View Code

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title></title>
    <style type="text/css">

    /*reset*/
    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}
    body,button,input,select,textarea{font:normal 14px/1.5 Tahoma,"Lucida Grande",Verdana,"Microsoft YaHei",hei;}
    article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section,iframe{display:block;}
    h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:500;}
    address,cite,dfn,em,var,i{font-style:normal;font-weight:normal;font-family:arial;}
    ul,ol{list-style:none}
    a{color:#000;text-decoration:none}
    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;}
    fieldset,img,button,input{border:0}
    button,input,select,textarea{font-size:100%}
    table{border-collapse:collapse;border-spacing:0}
    input[type="button"],input[type="submit"]{-webkit-appearance:none;}
    body{min-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;}
    html,body,.h100{ height:100%; }
    dfn{color:#ff9913; font-size:12px; font-weight:normal;}
    /*-----------------------------------------common--------------------*/
    .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;}
    .i_bef:before,.i_aft:after,.carlist li:before{position: absolute;content: "";}
    .abs_size{-moz-box-sizing:border-box; -webkit-box-sizing:border-box; box-sizing:border-box;}
    .opacity{opacity:0.7; filter:alpha(opacity=70);}

    /*active*/
    .list_st_border li:active,.p_hinttxt:active,.search_cancel:active,.citylist dd:active{ background:#f8f8f8;}
    .btn_yellow:active{background:#eb840f;}

    /*layout*/
    .wrap{margin-top:48px;}
    .wrap_pb{margin-top:48px; padding-bottom:45px;}
    .p10{padding:10px;}
    .hm{text-align:center;}
    .break_all{word-break:break-all;}
    .fix_b{position:fixed; bottom:0; left:0;z-index:9999;}

    /*font bg color size*/
    h1{font:normal 1.286em/1.5 "";}/*18px*/
    h2{font:normal 1.143em/1.5 "";}/*16px*/
    h3{font:600 1em/1.5 "";}/*14px*/
    .price{margin-left:5px;}
    .price i{margin-left:2px; font-size:1.286em;}
    .greyfont{color:#686868;}
    .greyfont1{color:#909090;}
    .bggrey{height:100%; background:#f5f5f5;}

    /*header*/
    header{position:fixed; top:0; left:0; z-index:9999; 100%; height:48px;background-color:#1491c5;}
    .returnico{position:absolute; left:0; top:0; 68px; height:48px; background-color:#15a4d5;}
    .returnico:before{left:25px;top:16px;12px;height:20px; background-position:0 0;}
    .icon_phone,.icon_home{42px;height:100%;top:0;position:relative;float:right;}
    .icon_phone:before{11px;height:20px;top:16px;right:12px;background-position:-115px -65px;}
    .icon_home:before{20px;height:19px;top:16px;right:10px;background-position:-83px -66px;}
    header i:active{opacity:0.7; filter:alpha(opacity=70);}
    header h1{position:absolute; 100%;line-height:48px; text-align:center; letter-spacing:2px; color: #fff;}
    .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;}
    .header_rs{padding:0 5px; font-size:12px; }

    /*background-position*/
    .select_n:before{20px;height:20px;background-position:-18px 0;}
    .select_n.current:before{background-position:-44px 0;}

    /*searchbox*/
    .search_wrap{overflow:hidden; padding:10px; background:#dfeaf1;}
    .search_box{position:relative; float:left; 100%;}
    .search_input{100%; padding:0 10px 0 28px; line-height:30px; background-color:#fff; border-radius:4px; color:#ccc;}
    .fdj:before,.fdj:after,.search_box:before,.search_box:after{position:absolute; content:""; z-index:9;}
    .fdj:before,.search_box:before{left:5px; top:7px; 12px; height:12px; border:1px solid #bcbcbc; border-radius:12px;}
    .fdj:after,.search_box:after{left:19px; top:17px; 1px; height:8px; background:#bcbcbc;}
    .search_cancel{ display:none;float:left; 20%; line-height:30px; text-align:center; font-size:16px;color:#1491c5; background:none; border:none;}
    .close_icon{display:none; position:absolute; z-index:10; top:8px; right:4px; 16px; height:16px; border-radius:30px; background:#b1b1b1;}
    .close_icon:before,.close_icon:after{position:absolute; content:""; top:4px; left:7px; 2px; height:8px; background:#fff; }
    .close_icon:before{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);}
    .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);}
    .search_focus .search_box{80%;}
    .search_focus .close_icon, .search_focus .search_cancel{display:block;}
    .search_input:focus{color:#000;}

    /*tab*/
    .tab{ background-color:#f8f8f8; border-bottom:1px solid #dfdfdf;}
    .tab li{float:left; 50%; height:39px; line-height:39px; text-align:center; border-right:1px solid #dfdfdf;}
    .tab li:last-child{border-right:none;}
    .tab li.tabcrt{ background-color:#dfdfdf;}

    .tab_b{ background-color:#f5f5f5; border-bottom:1px solid #c1c1c1;}
    .tab_b li{float:left; 50%; height:39px; line-height:39px; text-align:center;}
    .tab_b li:last-child{border-right:none;}
    .tab_b li.tabcrt{color:#1491c5; border-bottom:4px solid #1491c5;}

    /*list*/
    .list_st_border{ background:#fff; border-bottom:none; border:1px solid #cfcfcf; }
    .list_st_border li{position:relative;padding:0 10px; line-height:42px; border-bottom:1px solid #cfcfcf;}
    .list_st_border li:last-child{border-bottom:none;}

    .list_sli{padding:10px; overflow:hidden; border-bottom:1px solid #cfcfcf; background:#fff;}
    .list_sli .list_sunit{float:left;}

    .citylist{color:#000;}
    .citylist dt,.citylist dd{padding-left:10px;border-bottom:1px solid #e2e2e2;}
    .citylist dt{line-height:25px; background-color:#eaeaea;}
    .citylist dd{position:relative; font-size:16px; line-height:43px; background-color:#fff;}
    .citylist .ok_crt{color:#1491c5;}
    .citylist .ok_crt:after{position:absolute;content:""; right:10px; top:50%; margin-top:-6px; 12px; height:13px; background-position:-110px 0;}


    /*arr*/
    .li_arr_r{position:relative;}
    .arr_r{position:absolute;right:0px; top:50%; 30px; height:30px; margin-top:-15px; }
    .arr_r:before,.arr_r:after,.li_arr_r:before,.li_arr_r:after{position: absolute; left:15px; content: "";2px; height:7px; background-color:#909090;}
    .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);}
    .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);}
    .li_arr_r:before,.li_arr_r:after{left:auto; right:10px; top:50%; margin-top:-5px;}
    .li_arr_r:after{margin-top:0;}

    /*p*/
    .p_grey{margin:10px 5px; font-size:13px; color:#989898;}
    .p_grey_center{ text-align:center; margin:20px 5px; font-size:13px; color:#989898;}
    .p_hinttxt{padding:20px 10px; text-align:center; font-size:16px; color:#1491c5;}


    /*btn*/
    .btn_yellow,.btn_del{100%; height:44px; line-height:42px; padding:0 10px; color:#fff;}
    .btn_yellow{background:#ff9913;}
    .btn_del{background:#ca4345;text-align:center;font-size:1.2em;}

    .btn_pay{padding:0 20px;height:44px;float:right;background:#ff7d13;color:#fff;}
    .btn_pay:active{background:#ff7300;}
    .room_num {position:absolute; right:10px; 100px; height:30px; line-height:30px;color:#000;background-color: #fff; text-align:center;border:#bfbfbf 1px solid;}
    .room_num i{position:absolute; 30px; height:30px; text-align:center; font:normal 2em/28px "Arial";}
    .room_num i:first-child{left:0;background:#f4f4f4;color:#d9d9d9;font:normal 2.8em/25px "Arial";}
    .room_num i:last-child{right:0;background:#06a2d0;color:#fff;}


    /*日历*/
    .cui_cldwrap{color:#000;}
    .cui_cldweek{height:25px; overflow:hidden;font:normal 12px/24px "verdana";border-bottom:1px solid #c8c8c8;}
    .cui_cldweek li{float:left; 14%; text-align:center; }
    .cui_cldweek li:first-child,.cui_cldweek li:last-child{15%; color:#acacac;}
    .cui_cldmonth{height:35px;text-align:center;font:normal 16px/35px "verdana"; background:#fff;}
    .cui_cldunit{margin-bottom:20px;}
    .cui_cld_daybox{overflow:hidden; background:#fff;}
    .cui_cld_daybox li{float:left; 14%; height:45px; padding:4px 0; font:normal 12px/45px "verdana"; overflow:hidden; text-align:center;}
    .cui_cld_daybox li:nth-child(7n),.cui_cld_daybox li:nth-child(7n+1){15%;}
    .cui_cld_daypass{ background:#f7f7f7;}
    .cui_cld_daycrt{background:#06a2d0; color:#fff;}
    .cui_cld_dayfuture{background:#fff;}
    .cui_cld_day_nocrtmonth{ visibility:hidden;}
    .cui_cld_day_havetxt em{display:block; line-height:25px;}
    .cui_cld_day_havetxt i{display:block;line-height:15px;}
    .cui_cld_day_hint{color:#06a2d0;}
    /*全局XXXX*/

    /*弹出蓝色框*/
    .cui-pop-box{background:#fff;}
    .cui-text-center{text-align:center;}
    .cui-pop-box .cui-hd{height:40px;line-height:40px;font-size:1.2em;color:#fff;background:#1491c5;padding:0 10px;position:relative;}
    .cui-pop-box .cui-hd .cui-close{position:absolute;top:10px; right:10px; 18px; height:18px;line-height:18px;border-radius:50%; background:#fff;color:#1491c5;text-align:center;font-weight:bold;}
    .cui-error{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;}
    .cui-select-view li{border-bottom:#dfdfdf 1px solid;padding:.8em 2em .8em .8em;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;position:relative;}
    .cui-select-view li.current{color:#1084bc;}
    .cui-select-view li:active{background:rgba(0,0,0,.05);}
    .cui-select-view li.current:before,.cui-select-view li.current:after{position:absolute;content:"";background:#1084bc;height:3px;top:50%;border-radius:3px;}
    .cui-select-view li.current:before{18px;right:10px;margin-top:-2px;-webkit-transform:rotate(-50deg);-moz-transform:rotate(-50deg);-ms-transform:rotate(-50deg);transform:rotate(-50deg);}
    .cui-select-view li.current:after{9px;right:22px;margin-top:2px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);}

    .cui-roller{100%;height:90px;overflow:hidden;position:relative;display: -webkit-box;display: -moz-box;display: -ms-flexbox;display: -webkit-flex;display: flex;}
    .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;}
    .cui-mask{position:absolute;z-index:3;top: 0;left: 0; 100%;height: 100%;pointer-events: none;
    background: linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%);
    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));
    background: -webkit-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%);
    background: -moz-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%);
    }
    .cui-lines{100%;height:34px;position:absolute;top:50%;margin-top:-17px;border-top:#dfdfdf 1px solid;border-bottom:#dfdfdf 1px solid;}
    .cui-roller-tips{color:#8d8d8d;padding:5px;text-align:center;}
    .cui-roller-btns{background:#f6f5f5;padding:10px;text-align:center;}
    .cui-roller-btns span{45%;display:inline-block;padding:10px 0;color:#fff;}
    .cui-roller-btns span:active{opacity:.75;}
    .cui-roller-btns .cui-btns-cancel{background:#a9a9a9;margin-right:5%;}
    .cui-roller-btns .cui-btns-sure{background:#ff9913;}

    </style>

    <script id="others_zepto_10rc1" type="text/javascript" class="library" src="/js/sandbox/other/zepto.min.js"></script>
    </head>
    <body onselectstart="return false">
    <div class="cui-pop-box">
    <div class="cui-hd">
    <div class="cui-text-center">
    滚轮滚轮滚轮</div>
    </div>
    <div class="cui-bd">
    <div id="ctripPage">
    </div>
    <p class="cui-roller-tips">
    提示信息</p>
    <div class="cui-roller-btns">
    <span class="cui-btns-sure" id="set">设置值</span> <span class="cui-btns-sure" id="get">
    获取值</span>
    </div>
    </div>
    </div>
    <script type="text/javascript">

    // var myScroll = new iScroll('wl1');

    (function () {
    //!!!由于动画原因,获取值可能会出现不准确的情况,比如正在动画却已经取值了
    //所以设置了一个冷却时间,在冷却时间的情况下设置值等操作不能进行
    //为了保证唯一性,全部使用index作为索引算了
    var ScrollRadio = function (opts) {
    opts = opts || {};
    //容器元素
    this.wrapper = opts.wrapper || $(document);
    this.body = [
    '<div class="cui-roller">',
    '<ul class="ul-list" style=" position: absolute; 100%; z-index: 2; " >',
    '</ul>',
    '<div class="cui-mask"></div>',
    '<div class="cui-lines">&nbsp;</div>',
    '</div>'
    ].join('');
    this.body = $(this.body);

    //真正拖动的元素(现在是ul)
    this.dragEl = this.body.find('.ul-list');
    //数据源
    this.data = opts.data || [];
    this._changed = opts.changed || null;
    //当前选项索引默认选择2项
    this.selectedIndex = 1;

    //当前选项值
    // this.key = '';
    //当前选项显示的值
    // this.value = '';

    /*
    定位实际需要用到的信息
    暂时不考虑水平移动吧
    */
    this.itemHeight = 0; //单个item高度
    this.dragHeight = 0; //拖动元素高度
    this.dragTop = 0; //拖动元素top
    this.animateParam = [10, 6, 2, 1, 0, 0, 0, 0, 0, 0, 0]; //动画参数
    this.timeGap = 0; //时间间隔
    this.touchTime = 0; //开始时间
    this.moveAble = false; //是否正在移动
    this.moveState = 'up'; //移动状态,up right down left
    this.oTop = 0; //拖动前的top值
    this.curTop = 0; //当前容器top
    this.mouseY = 0; //鼠标第一次点下时相对父容器的位置
    this.cooling = false; //是否处于冷却时间

    this.init();
    };
    ScrollRadio.prototype = {
    constructor: ScrollRadio,
    init: function () {
    this.initItem();
    this.wrapper.append(this.body);
    this.initEventParam();
    this.bindEvent();

    return this;
    },
    //增加数据
    initItem: function () {
    var _tmp, _data, i, k;
    for (var i in this.data) {
    _data = this.data[i]
    _tmp = $('<li>' + (_data.val == undefined ? i : _data.val) + '</li>');
    _tmp.attr('data-index', i);
    for (k in _data) {
    _tmp.attr('data-' + k, _data[k]);
    }
    this.dragEl.append(_tmp);
    }
    },
    //初始化事件需要用到的参数信息
    initEventParam: function () {
    var offset = this.dragEl.offset();
    var itemOffset = this.dragEl.find('li').eq(0).offset();
    this.itemHeight = itemOffset.height
    this.dragTop = offset.top;
    this.dragHeight = this.dragEl[0].scrollHeight;
    var s = '';
    },
    bindEvent: function () {
    var scope = this;
    document.addEventListener("touchstart", function (e) {
    scope.touchStart.call(scope, e);
    }, false);
    document.addEventListener("touchend", function (e) {
    scope.touchEnd.call(scope, e);
    }, false);
    document.addEventListener("touchmove", function (e) {
    scope.touchMove.call(scope, e);
    }, false);
    },
    touchStart: function (e) {
    if (this.cooling) return false; //冷却时间不能开始

    //需要判断是否是拉取元素,此处需要递归验证,这里暂时不管
    //!!!!!!!!此处不严谨
    var el = $(e.srcElement).parent(), pos;
    if (el.hasClass('ul-list')) {
    this.moveAble = true;

    this.touchTime = e.timeStamp;
    //获取鼠标信息
    pos = this.getMousePos(e.changedTouches[0]);
    //注意,此处是相对位置,注意该处还与动画有关,所以高度必须动态计算
    //可以设置一个冷却时间参数,但想想还是算了
    //最后还是使用了冷却时间
    // var top = parseFloat(this.dragEl.css('top')) || 0;
    // this.mouseY = pos.top - top;
    this.mouseY = pos.top - this.curTop;
    this.moveAble = true;
    }
    },
    touchMove: function (e) {
    if (!this.moveAble) return false;
    var pos = this.getMousePos(e.changedTouches[0]);
    //先获取相对容器的位置,在将两个鼠标位置相减
    this.curTop = pos.top - this.mouseY;
    this.dragEl.css('top', this.curTop + 'px');
    e.preventDefault();
    },
    touchEnd: function (e) {
    if (!this.moveAble) return false;
    this.cooling = true; //开启冷却时间

    //时间间隔
    var scope = this;
    this.timeGap = e.timeStamp - this.touchTime;
    var flag = this.oTop <= this.curTop ? 1 : -1; //判断是向上还是向下滚动
    var flag2 = this.curTop > 0 ? 1 : -1; //这个会影响后面的计算结果
    this.moveState = flag > 0 ? 'up' : 'down';
    var ih = parseFloat(this.itemHeight);
    var ih1 = ih / 2;

    var top = Math.abs(this.curTop);
    var mod = top % ih;
    top = (parseInt(top / ih) * ih + (mod > ih1 ? ih : 0)) * flag2;

    var step = parseInt(this.timeGap / 50);
    step = step > 0 ? step : 0;
    var speed = this.animateParam[step] || 0;
    var increment = speed * ih * flag
    top += increment;
    //!!!此处动画可能导致数据不同步,后期改造需要加入冷却时间
    if (this.oTop != this.curTop) {
    this.dragEl.animate({
    top: top + 'px'
    }, 100 + (speed * 20), 'ease-out', function () {
    var _top = top, t = false; ;
    if (top > ih) {
    _top = ih;
    t = true;
    }
    if (top < 0 && (top + scope.dragHeight < ih * 2)) {
    t = true;
    _top = (scope.dragHeight - ih * 2) * (-1);
    }
    if (t) {
    scope.dragEl.animate({
    top: _top + 'px'
    }, 10, 'ease-in-out', function () {
    scope.oTop = _top;
    scope.curTop = _top;
    scope.cooling = false; //关闭冷却时间
    scope.onTouchEnd();
    });
    } else {
    scope.cooling = false; //关闭冷却时间
    scope.oTop = top;
    scope.curTop = top;
    scope.onTouchEnd();
    }
    });
    } else {
    this.cooling = false; //关闭冷却时间
    this.onTouchEnd();
    }
    this.moveAble = false;
    },
    onTouchEnd: function () {
    var i = parseInt((this.curTop - this.itemHeight) / parseFloat(this.itemHeight));
    this.selectedIndex = Math.abs(i);
    var secItem = this.data[this.selectedIndex];
    //触发变化事件
    var changed = this._changed;
    if (changed && typeof changed == 'function') {
    changed.call(this, secItem);
    }
    console.log(this.selectedIndex, secItem);
    },
    setKey: function (k) { },
    setVal: function (v) { },
    setIndex: function (i) {
    var i = parseInt(i);
    if (i >= this.data.length || i < 0) return false;

    this.selectedIndex = i;
    this.curTop = (i * this.itemHeight * (-1) + this.itemHeight);
    this.dragEl.css('top', this.curTop + 'px');
    },
    getSelected: function () {
    return this.data[this.selectedIndex];
    },
    getByKey: function (k) { },
    getByVal: function (v) { },
    getByIndex: function (i) { },
    //获取鼠标信息
    getMousePos: function (event) {
    var top, left;
    top = Math.max(document.body.scrollTop, document.documentElement.scrollTop);
    left = Math.max(document.body.scrollLeft, document.documentElement.scrollLeft);
    return {
    top: top + event.clientY,
    left: left + event.clientX
    };
    }
    };
    window.ScrollRadio = ScrollRadio;

    })();

    var data = [];
    for (var i = 0; i < 20; i++) {
    var temp = { val: '选项-' + i };
    data.push(temp);
    }

    var myScroll = new ScrollRadio({
    wrapper: $('#ctripPage'),
    data: data
    });

    $('#set').click(function () {
    var i = prompt("请输入索引值")
    if (i != null && i != "") {
    myScroll.setIndex(i);
    }
    });

    $('#get').click(function () {
    var d = myScroll.getSelected();
    var str = '';
    for (var k in d) {
    str += k + ': ' + d[k] + ',';
    }
    alert(str);
    });

    var s = '';

    </script>
    </body>
    </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;  100%; z-index: 2;  " >',
     12         '</ul>',
     13         '<div class="cui-mask"></div>',
     14         '<div class="cui-lines">&nbsp;</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

     View Code

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title></title>
    <style type="text/css">

    /*reset*/
    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}
    body,button,input,select,textarea{font:normal 14px/1.5 Tahoma,"Lucida Grande",Verdana,"Microsoft YaHei",hei;}
    article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section,iframe{display:block;}
    h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:500;}
    address,cite,dfn,em,var,i{font-style:normal;font-weight:normal;font-family:arial;}
    ul,ol{list-style:none}
    a{color:#000;text-decoration:none}
    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;}
    fieldset,img,button,input{border:0}
    button,input,select,textarea{font-size:100%}
    table{border-collapse:collapse;border-spacing:0}
    input[type="button"],input[type="submit"]{-webkit-appearance:none;}
    body{min-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;}
    html,body,.h100{ height:100%; }
    dfn{color:#ff9913; font-size:12px; font-weight:normal;}
    /*-----------------------------------------common--------------------*/
    .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;}
    .i_bef:before,.i_aft:after,.carlist li:before{position: absolute;content: "";}
    .abs_size{-moz-box-sizing:border-box; -webkit-box-sizing:border-box; box-sizing:border-box;}
    .opacity{opacity:0.7; filter:alpha(opacity=70);}

    /*active*/
    .list_st_border li:active,.p_hinttxt:active,.search_cancel:active,.citylist dd:active{ background:#f8f8f8;}
    .btn_yellow:active{background:#eb840f;}

    /*layout*/
    .wrap{margin-top:48px;}
    .wrap_pb{margin-top:48px; padding-bottom:45px;}
    .p10{padding:10px;}
    .hm{text-align:center;}
    .break_all{word-break:break-all;}
    .fix_b{position:fixed; bottom:0; left:0;z-index:9999;}

    /*font bg color size*/
    h1{font:normal 1.286em/1.5 "";}/*18px*/
    h2{font:normal 1.143em/1.5 "";}/*16px*/
    h3{font:600 1em/1.5 "";}/*14px*/
    .price{margin-left:5px;}
    .price i{margin-left:2px; font-size:1.286em;}
    .greyfont{color:#686868;}
    .greyfont1{color:#909090;}
    .bggrey{height:100%; background:#f5f5f5;}

    /*header*/
    header{position:fixed; top:0; left:0; z-index:9999; 100%; height:48px;background-color:#1491c5;}
    .returnico{position:absolute; left:0; top:0; 68px; height:48px; background-color:#15a4d5;}
    .returnico:before{left:25px;top:16px;12px;height:20px; background-position:0 0;}
    .icon_phone,.icon_home{42px;height:100%;top:0;position:relative;float:right;}
    .icon_phone:before{11px;height:20px;top:16px;right:12px;background-position:-115px -65px;}
    .icon_home:before{20px;height:19px;top:16px;right:10px;background-position:-83px -66px;}
    header i:active{opacity:0.7; filter:alpha(opacity=70);}
    header h1{position:absolute; 100%;line-height:48px; text-align:center; letter-spacing:2px; color: #fff;}
    .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;}
    .header_rs{padding:0 5px; font-size:12px; }

    /*background-position*/
    .select_n:before{20px;height:20px;background-position:-18px 0;}
    .select_n.current:before{background-position:-44px 0;}

    /*searchbox*/
    .search_wrap{overflow:hidden; padding:10px; background:#dfeaf1;}
    .search_box{position:relative; float:left; 100%;}
    .search_input{100%; padding:0 10px 0 28px; line-height:30px; background-color:#fff; border-radius:4px; color:#ccc;}
    .fdj:before,.fdj:after,.search_box:before,.search_box:after{position:absolute; content:""; z-index:9;}
    .fdj:before,.search_box:before{left:5px; top:7px; 12px; height:12px; border:1px solid #bcbcbc; border-radius:12px;}
    .fdj:after,.search_box:after{left:19px; top:17px; 1px; height:8px; background:#bcbcbc;}
    .search_cancel{ display:none;float:left; 20%; line-height:30px; text-align:center; font-size:16px;color:#1491c5; background:none; border:none;}
    .close_icon{display:none; position:absolute; z-index:10; top:8px; right:4px; 16px; height:16px; border-radius:30px; background:#b1b1b1;}
    .close_icon:before,.close_icon:after{position:absolute; content:""; top:4px; left:7px; 2px; height:8px; background:#fff; }
    .close_icon:before{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);}
    .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);}
    .search_focus .search_box{80%;}
    .search_focus .close_icon, .search_focus .search_cancel{display:block;}
    .search_input:focus{color:#000;}

    /*tab*/
    .tab{ background-color:#f8f8f8; border-bottom:1px solid #dfdfdf;}
    .tab li{float:left; 50%; height:39px; line-height:39px; text-align:center; border-right:1px solid #dfdfdf;}
    .tab li:last-child{border-right:none;}
    .tab li.tabcrt{ background-color:#dfdfdf;}

    .tab_b{ background-color:#f5f5f5; border-bottom:1px solid #c1c1c1;}
    .tab_b li{float:left; 50%; height:39px; line-height:39px; text-align:center;}
    .tab_b li:last-child{border-right:none;}
    .tab_b li.tabcrt{color:#1491c5; border-bottom:4px solid #1491c5;}

    /*list*/
    .list_st_border{ background:#fff; border-bottom:none; border:1px solid #cfcfcf; }
    .list_st_border li{position:relative;padding:0 10px; line-height:42px; border-bottom:1px solid #cfcfcf;}
    .list_st_border li:last-child{border-bottom:none;}

    .list_sli{padding:10px; overflow:hidden; border-bottom:1px solid #cfcfcf; background:#fff;}
    .list_sli .list_sunit{float:left;}

    .citylist{color:#000;}
    .citylist dt,.citylist dd{padding-left:10px;border-bottom:1px solid #e2e2e2;}
    .citylist dt{line-height:25px; background-color:#eaeaea;}
    .citylist dd{position:relative; font-size:16px; line-height:43px; background-color:#fff;}
    .citylist .ok_crt{color:#1491c5;}
    .citylist .ok_crt:after{position:absolute;content:""; right:10px; top:50%; margin-top:-6px; 12px; height:13px; background-position:-110px 0;}


    /*arr*/
    .li_arr_r{position:relative;}
    .arr_r{position:absolute;right:0px; top:50%; 30px; height:30px; margin-top:-15px; }
    .arr_r:before,.arr_r:after,.li_arr_r:before,.li_arr_r:after{position: absolute; left:15px; content: "";2px; height:7px; background-color:#909090;}
    .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);}
    .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);}
    .li_arr_r:before,.li_arr_r:after{left:auto; right:10px; top:50%; margin-top:-5px;}
    .li_arr_r:after{margin-top:0;}

    /*p*/
    .p_grey{margin:10px 5px; font-size:13px; color:#989898;}
    .p_grey_center{ text-align:center; margin:20px 5px; font-size:13px; color:#989898;}
    .p_hinttxt{padding:20px 10px; text-align:center; font-size:16px; color:#1491c5;}


    /*btn*/
    .btn_yellow,.btn_del{100%; height:44px; line-height:42px; padding:0 10px; color:#fff;}
    .btn_yellow{background:#ff9913;}
    .btn_del{background:#ca4345;text-align:center;font-size:1.2em;}

    .btn_pay{padding:0 20px;height:44px;float:right;background:#ff7d13;color:#fff;}
    .btn_pay:active{background:#ff7300;}
    .room_num {position:absolute; right:10px; 100px; height:30px; line-height:30px;color:#000;background-color: #fff; text-align:center;border:#bfbfbf 1px solid;}
    .room_num i{position:absolute; 30px; height:30px; text-align:center; font:normal 2em/28px "Arial";}
    .room_num i:first-child{left:0;background:#f4f4f4;color:#d9d9d9;font:normal 2.8em/25px "Arial";}
    .room_num i:last-child{right:0;background:#06a2d0;color:#fff;}


    /*日历*/
    .cui_cldwrap{color:#000;}
    .cui_cldweek{height:25px; overflow:hidden;font:normal 12px/24px "verdana";border-bottom:1px solid #c8c8c8;}
    .cui_cldweek li{float:left; 14%; text-align:center; }
    .cui_cldweek li:first-child,.cui_cldweek li:last-child{15%; color:#acacac;}
    .cui_cldmonth{height:35px;text-align:center;font:normal 16px/35px "verdana"; background:#fff;}
    .cui_cldunit{margin-bottom:20px;}
    .cui_cld_daybox{overflow:hidden; background:#fff;}
    .cui_cld_daybox li{float:left; 14%; height:45px; padding:4px 0; font:normal 12px/45px "verdana"; overflow:hidden; text-align:center;}
    .cui_cld_daybox li:nth-child(7n),.cui_cld_daybox li:nth-child(7n+1){15%;}
    .cui_cld_daypass{ background:#f7f7f7;}
    .cui_cld_daycrt{background:#06a2d0; color:#fff;}
    .cui_cld_dayfuture{background:#fff;}
    .cui_cld_day_nocrtmonth{ visibility:hidden;}
    .cui_cld_day_havetxt em{display:block; line-height:25px;}
    .cui_cld_day_havetxt i{display:block;line-height:15px;}
    .cui_cld_day_hint{color:#06a2d0;}
    /*全局XXXX*/

    /*弹出蓝色框*/
    .cui-pop-box{background:#fff;}
    .cui-text-center{text-align:center;}
    .cui-pop-box .cui-hd{height:40px;line-height:40px;font-size:1.2em;color:#fff;background:#1491c5;padding:0 10px;position:relative;}
    .cui-pop-box .cui-hd .cui-close{position:absolute;top:10px; right:10px; 18px; height:18px;line-height:18px;border-radius:50%; background:#fff;color:#1491c5;text-align:center;font-weight:bold;}
    .cui-error{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;}
    .cui-select-view li{border-bottom:#dfdfdf 1px solid;padding:.8em 2em .8em .8em;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;position:relative;}
    .cui-select-view li.current{color:#1084bc;}
    .cui-select-view li:active{background:rgba(0,0,0,.05);}
    .cui-select-view li.current:before,.cui-select-view li.current:after{position:absolute;content:"";background:#1084bc;height:3px;top:50%;border-radius:3px;}
    .cui-select-view li.current:before{18px;right:10px;margin-top:-2px;-webkit-transform:rotate(-50deg);-moz-transform:rotate(-50deg);-ms-transform:rotate(-50deg);transform:rotate(-50deg);}
    .cui-select-view li.current:after{9px;right:22px;margin-top:2px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);}

    .cui-roller{100%;height:90px;overflow:hidden;position:relative;display: -webkit-box;display: -moz-box;display: -ms-flexbox;display: -webkit-flex;display: flex;}
    .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;}
    .cui-mask{position:absolute;z-index:3;top: 0;left: 0; 100%;height: 100%;pointer-events: none;
    background: linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%);
    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));
    background: -webkit-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%);
    background: -moz-linear-gradient(#fff 0,rgba(245,245,245,0) 52%,rgba(245,245,245,0) 48%,#fff 100%);
    }
    .cui-lines{100%;height:34px;position:absolute;top:50%;margin-top:-17px;border-top:#dfdfdf 1px solid;border-bottom:#dfdfdf 1px solid;}
    .cui-roller-tips{color:#8d8d8d;padding:5px;text-align:center;}
    .cui-roller-btns{background:#f6f5f5;padding:10px;text-align:center;}
    .cui-roller-btns span{45%;display:inline-block;padding:10px 0;color:#fff;}
    .cui-roller-btns span:active{opacity:.75;}
    .cui-roller-btns .cui-btns-cancel{background:#a9a9a9;margin-right:5%;}
    .cui-roller-btns .cui-btns-sure{background:#ff9913;}

    </style>
    <style type="text/css">
    .c { position: absolute; top: 0; }
    #y { left: 0; 30%; }
    #m { left: 30%; right: 40%; }
    #d { right: 0; 40%; }
    </style>
    <script src="../zepto.js" type="text/javascript"></script>
    </head>
    <body onselectstart="return false">
    <div class="cui-pop-box">
    <div class="cui-hd">
    <div class="cui-text-center">
    我是日历控件</div>
    </div>
    <div class="cui-bd">
    <div style="height: 90px; position: relative;">
    <div id="y" class="c">
    </div>
    <div id="m" class="c">
    </div>
    <div id="d" class="c">
    </div>
    </div>
    <p class="cui-roller-tips">
    点击获取日期吧!</p>
    <div class="cui-roller-btns">
    <span class="cui-btns-cancel" id="set">取消</span> <span class="cui-btns-sure" id="get">
    获取日期</span>
    </div>
    </div>
    </div>

    <script type="text/javascript">

    // var myScroll = new iScroll('wl1');

    (function () {
    //!!!由于动画原因,获取值可能会出现不准确的情况,比如正在动画却已经取值了
    //所以设置了一个冷却时间,在冷却时间的情况下设置值等操作不能进行
    //为了保证唯一性,全部使用index作为索引算了
    var ScrollRadio = function (opts) {
    opts = opts || {};
    //容器元素
    this.wrapper = opts.wrapper || $(document);
    var id = new Date().getTime() + Math.random() + 'id';
    this.body = [
    '<div class="cui-roller">',
    '<ul class="ul-list" style=" position: absolute; 100%; z-index: 2; " id="' + id + '" >',
    '</ul>',
    '<div class="cui-mask"></div>',
    '<div class="cui-lines">&nbsp;</div>',
    '</div>'
    ].join('');
    this.body = $(this.body);

    //真正拖动的元素(现在是ul)
    this.dragEl = this.body.find('.ul-list');
    //数据源
    this.data = opts.data || [];
    this._changed = opts.changed || null;
    //当前选项索引默认选择2项
    this.selectedIndex = 1;

    //当前选项值
    // this.key = '';
    //当前选项显示的值
    // this.value = '';

    /*
    定位实际需要用到的信息
    暂时不考虑水平移动吧
    */
    this.itemHeight = 0; //单个item高度
    this.dragHeight = 0; //拖动元素高度
    this.dragTop = 0; //拖动元素top
    this.animateParam = [10, 6, 2, 1, 0, 0, 0, 0, 0, 0, 0]; //动画参数
    this.timeGap = 0; //时间间隔
    this.touchTime = 0; //开始时间
    this.moveAble = false; //是否正在移动
    this.moveState = 'up'; //移动状态,up right down left
    this.oTop = 0; //拖动前的top值
    this.curTop = 0; //当前容器top
    this.mouseY = 0; //鼠标第一次点下时相对父容器的位置
    this.cooling = false; //是否处于冷却时间

    this.init();
    };
    ScrollRadio.prototype = {
    constructor: ScrollRadio,
    init: function () {
    this.initItem();
    this.wrapper.append(this.body);
    this.initEventParam();
    this.bindEvent();
    },
    //增加数据
    initItem: function () {
    var _tmp, _data, i, k;
    for (var i in this.data) {
    _data = this.data[i]
    _tmp = $('<li>' + (_data.val == undefined ? i : _data.val) + '</li>');
    _tmp.attr('data-index', i);
    for (k in _data) {
    _tmp.attr('data-' + k, _data[k]);
    }
    this.dragEl.append(_tmp);
    }
    },
    //初始化事件需要用到的参数信息
    initEventParam: function () {
    var offset = this.dragEl.offset();
    var itemOffset = this.dragEl.find('li').eq(0).offset();
    this.itemHeight = itemOffset.height
    this.dragTop = offset.top;
    this.dragHeight = this.dragEl[0].scrollHeight;
    var s = '';
    },
    bindEvent: function () {
    var scope = this;
    this.dragEl[0].addEventListener("touchstart", function (e) {
    scope.touchStart.call(scope, e);
    }, false);
    this.dragEl[0].addEventListener("touchend", function (e) {
    scope.touchEnd.call(scope, e);
    }, false);
    this.dragEl[0].addEventListener("touchmove", function (e) {
    scope.touchMove.call(scope, e);
    }, false);
    },
    touchStart: function (e) {
    if (this.cooling) return false; //冷却时间不能开始

    //需要判断是否是拉取元素,此处需要递归验证,这里暂时不管
    //!!!!!!!!此处不严谨
    var el = $(e.srcElement).parent(), pos;
    if (el.hasClass('ul-list')) {
    this.moveAble = true;

    this.touchTime = e.timeStamp;
    //获取鼠标信息
    pos = this.getMousePos(e.changedTouches[0]);
    //注意,此处是相对位置,注意该处还与动画有关,所以高度必须动态计算
    //可以设置一个冷却时间参数,但想想还是算了
    //最后还是使用了冷却时间
    // var top = parseFloat(this.dragEl.css('top')) || 0;
    // this.mouseY = pos.top - top;
    this.mouseY = pos.top - this.curTop;
    this.moveAble = true;
    }
    },
    touchMove: function (e) {
    if (!this.moveAble) return false;
    var pos = this.getMousePos(e.changedTouches[0]);
    //先获取相对容器的位置,在将两个鼠标位置相减
    this.curTop = pos.top - this.mouseY;
    this.dragEl.css('top', this.curTop + 'px');
    e.preventDefault();
    },
    touchEnd: function (e) {
    if (!this.moveAble) return false;
    this.cooling = true; //开启冷却时间

    //时间间隔
    var scope = this;
    this.timeGap = e.timeStamp - this.touchTime;
    var flag = this.oTop <= this.curTop ? 1 : -1; //判断是向上还是向下滚动
    var flag2 = this.curTop > 0 ? 1 : -1; //这个会影响后面的计算结果
    this.moveState = flag > 0 ? 'up' : 'down';
    var ih = parseFloat(this.itemHeight);
    var ih1 = ih / 2;

    var top = Math.abs(this.curTop);
    var mod = top % ih;
    top = (parseInt(top / ih) * ih + (mod > ih1 ? ih : 0)) * flag2;

    var step = parseInt(this.timeGap / 50);
    step = step > 0 ? step : 0;
    var speed = this.animateParam[step] || 0;
    var increment = speed * ih * flag
    top += increment;
    //!!!此处动画可能导致数据不同步,后期改造需要加入冷却时间
    if (this.oTop != this.curTop) {
    this.dragEl.animate({
    top: top + 'px'
    }, 100 + (speed * 20), 'ease-out', function () {
    var _top = top, t = false; ;
    if (top > ih) {
    _top = ih;
    t = true;
    }
    if (top < 0 && (top + scope.dragHeight < ih * 2)) {
    t = true;
    _top = (scope.dragHeight - ih * 2) * (-1);
    }
    if (t) {
    scope.dragEl.animate({
    top: _top + 'px'
    }, 10, 'ease-in-out', function () {
    scope.oTop = _top;
    scope.curTop = _top;
    scope.cooling = false; //关闭冷却时间
    scope.onTouchEnd();
    });
    } else {
    scope.cooling = false; //关闭冷却时间
    scope.oTop = top;
    scope.curTop = top;
    scope.onTouchEnd();
    }
    });
    } else {
    this.cooling = false; //关闭冷却时间
    this.onTouchEnd();
    }
    this.moveAble = false;
    },
    onTouchEnd: function () {
    var i = parseInt((this.curTop - this.itemHeight) / parseFloat(this.itemHeight));
    this.selectedIndex = Math.abs(i);
    var secItem = this.data[this.selectedIndex];
    //触发变化事件
    var changed = this._changed;
    if (changed && typeof changed == 'function') {
    changed.call(this, secItem);
    }
    console.log(this.selectedIndex, secItem);
    },
    setKey: function (k) { },
    setVal: function (v) { },
    setIndex: function (i) {
    var i = parseInt(i);
    if (i >= this.data.length || i < 0) return false;

    this.selectedIndex = i;
    this.curTop = (i * this.itemHeight * (-1) + this.itemHeight);
    this.dragEl.css('top', this.curTop + 'px');
    },
    getSelected: function () {
    return this.data[this.selectedIndex];
    },
    getByKey: function (k) { },
    getByVal: function (v) { },
    getByIndex: function (i) { },
    //获取鼠标信息
    getMousePos: function (event) {
    var top, left;
    top = Math.max(document.body.scrollTop, document.documentElement.scrollTop);
    left = Math.max(document.body.scrollLeft, document.documentElement.scrollLeft);
    return {
    top: top + event.clientY,
    left: left + event.clientX
    };
    }
    };
    window.ScrollRadio = ScrollRadio;

    })();

    var yy = [];
    for (var i = 0; i < 150; i++) {
    var temp = { val: 1900 + i };
    yy.push(temp);
    }

    var mm = [];
    for (var i = 0; i < 12; i++) {
    var temp = { val: i > 10 ? i : (0 + '' + i) };
    mm.push(temp);
    }

    var dd = [];
    for (var i = 0; i < 31; i++) {
    var temp = { val: i > 10 ? i : (0 + '' + i) };
    dd.push(temp);
    }

    var y = new ScrollRadio({
    wrapper: $('#y'),
    data: yy
    });
    var m = new ScrollRadio({
    wrapper: $('#m'),
    data: mm
    });
    var d = new ScrollRadio({
    wrapper: $('#d'),
    data: dd
    });

    $('#get').click(function () {
    alert(y.getSelected().val + '-' + m.getSelected().val + '-' + d.getSelected().val);
    });

    var s = '';

    </script>
    </body>
    </html>

    今天时间用多了,老夫有点来不起了,我们下次再完善吧。。。。。。

    结语

    若是各位觉得有用的话不妨用一用,发现什么BUG请留言,我下次一并更新,BUG应该很多的。 

     
     
    分类: 移动开发
  • 相关阅读:
    JavaScript内置对象
    微信小程序:实现可拖动悬浮图标(包括按钮角标的实现)
    项目1——博客系统
    在HTML中使用css3实现雪人动画效果
    Ajax请求后台发送String类型总是进入Error function解决办法总结
    原生js实现图片懒加载
    【Electron Playground 系列】自定义协议篇
    大规格文件的上传优化
    如何优雅的在react-hook中进行网络请求
    noip2008 双栈排序
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3323684.html
Copyright © 2011-2022 走看看