日历插件(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应该很多的。 

 
 
分类: 移动开发
原文地址:https://www.cnblogs.com/Leo_wl/p/3323684.html