手机端上下滑动选择项小组件

这是一个手机端的滑动选择小组件。

详细的需求介绍:话费充值,滑动选择充值面额,显示对应的应付金额即可。

 

重点请看Javascript部分的代码,请大神指点。跪谢! 

 

贴代码~

CSS 部分:

  1 html, body, h1, h2, h3, p, dl, dd, ol, ul, th, td, form, fieldset, input, button, textarea, a {
  2   margin: 0;
  3   padding: 0; }
  4 
  5 html {
  6   -webkit-text-size-adjust: none;
  7   word-wrap: break-word;
  8   -webkit-touch-callout: none; }
  9 
 10 h1, h2, h3 {
 11   font-size: 100%; }
 12 
 13 ol, ul {
 14   list-style: none; }
 15 
 16 table {
 17   border-collapse: collapse;
 18   border-spacing: 0;
 19   empty-cells: show;
 20   font-size: inherit; }
 21 
 22 fieldset, img {
 23   border: 0; }
 24 
 25 cite, em, s, i, b {
 26   font-style: normal; }
 27 
 28 input, button, textarea, select {
 29   font-size: 100%; }
 30 
 31 body, input, button, textarea, select, option, optgroup {
 32   font-size: 14px; }
 33 
 34 a, input, textarea {
 35   text-decoration: none;
 36   outline: 0 none;
 37   resize: none;
 38   -webkit-tap-highlight-color: transparent; }
 39 
 40 li, img, label, input {
 41   vertical-align: middle; }
 42 
 43 img {
 44   display: block; }
 45 
 46 a {
 47   text-decoration: none; }
 48 
 49 body {
 50   font: 14px/1.2 "Microsoft Yahei","Hiragino Sans GB",arial,sans-serif; }
 51 
 52 .clearfix:after {
 53   display: block;
 54   content: "\20";
 55   height: 0;
 56   clear: both;
 57   overflow: hidden;
 58   visibility: hidden; }
 59 
 60 html, body {
 61   height: 100%;
 62   background-color: #f1f1f1; }
 63 
 64 /* sprite icon */
 65 .icon-lottery,
 66 .icon-phone,
 67 .icon-game,
 68 .icon-qq,
 69 .icon-hotel,
 70 .icon-plane,
 71 .icon-gas {
 72   display: inline-block;
 73   background: url(../img/base/sprite-icon.png) 0 0 no-repeat;
 74   height: 112px; }
 75 
 76 /* header */
 77 .header {
 78   position: fixed;
 79   top: 0;
 80   left: 0;
 81   width: 100%;
 82   height: 42px;
 83   line-height: 42px;
 84   background-color: #f16b50; }
 85 
 86 .header .title {
 87   font-size: 16px;
 88   color: #fff;
 89   text-align: center; }
 90 
 91 .header .icon-code-left {
 92   position: absolute;
 93   left: 0;
 94   top: 0;
 95   width: 34px;
 96   height: 42px;
 97   line-height: 42px;
 98   font-size: 16px;
 99   color: #fff;
100   font-weight: bold;
101   text-align: center; }
102 
103 .wrapper {
104   padding-top: 42px; }
105 
106 /* btn */
107 .btn {
108   display: inline-block;
109   background-color: #f16b50;
110   text-align: center;
111   color: #fff; }
112 
113 .btn-large {
114   width: 100%;
115   height: 40px;
116   line-height: 40px; }
117 
118 /* home index */
119 .icon-lottery {
120   background-position: 0 0;
121   width: 108px; }
122 
123 .icon-phone {
124   background-position: -108px 0;
125   width: 94px; }
126 
127 .icon-game {
128   background-position: -204px 0;
129   width: 108px; }
130 
131 .icon-qq {
132   background-position: -314px 0;
133   width: 99px; }
134 
135 .icon-hotel {
136   background-position: -415px 0;
137   width: 90px; }
138 
139 .icon-plane {
140   background-position: -507px 0;
141   width: 108px; }
142 
143 .icon-gas {
144   background-position: -618px 0;
145   width: 81px; }
146 
147 .recharge-list .r-l-item {
148   float: left;
149   width: 50%;
150   line-height: 1;
151   text-align: center; }
152 
153 .recharge-list a {
154   display: block;
155   padding: 58px 0; }
156 
157 .recharge-list .r-l-item.grey {
158   background-color: #eee; }
159 
160 .recharge-list .r-l-describe {
161   height: 22px;
162   line-height: 22px;
163   text-align: center;
164   color: #333; }
165 
166 /* list.html */
167 .w-list {
168   xxpadding: 0 22px 0 12px; }
169 
170 .w-list .w-l-index {
171   position: fixed;
172   top: 50%;
173   right: 0;
174   margin-top: -196px;
175   width: 22px;
176   text-align: center; }
177 
178 .w-list .w-l-index a {
179   color: #666; }
180 
181 .w-list .w-l-content dt {
182   border-bottom: 1px solid #ccc;
183   padding: 10px;
184   line-height: 1.2;
185   background-color: #f4f4f4;
186   font-size: 16px;
187   color: #f16b50; }
188 
189 .w-list .w-l-content dd {
190   border-bottom: 1px solid #ccc;
191   padding: 16px;
192   line-height: 1.4; }
193 
194 .w-list .w-l-content dd a {
195   font-size: 12px;
196   color: #333; }
197 
198 /* recharge.html */
199 .box-radius {
200   margin: 14px 20px 0;
201   border: 1px solid #ccc;
202   border-radius: 8px;
203   background-color: #FFF;
204   overflow: hidden; }
205 
206 .input-group .label,
207 .input-group .input-control {
208   display: block;
209   padding: 12px 8px; }
210 
211 .input-group .label {
212   line-height: 22px; }
213 
214 .input-group .input-control {
215   border: 0;
216   line-height: 22px;
217   width: 100%;
218   box-sizing: border-box;
219   background-color: transparent; }
220 
221 .input-group input.input-control {
222   border: 1px solid #fff;
223   border-top: 1px solid #ccc; }
224 
225 .input-group input.input-control:first-child {
226   margin-top: -1px; }
227 
228 .input-group input.input-control.error {
229   border-color: #f16b50;
230   border-radius: 7px; }
231 
232 .recharge .btn-area {
233   margin: 14px 20px 20px; }
234 
235 .recharge-list {
236   border-top: 1px solid #ccc;
237   height: 128px;
238   overflow: hidden; }
239 
240 .recharge-list .r-l-left {
241   position: relative;
242   float: left;
243   border-right: 1px solid #ccc;
244   width: 50%;
245   height: 100%;
246   xxoverflow: auto; }
247 
248 .recharge-list .r-l-right {
249   float: right;
250   padding: 46px 14px 0;
251   line-height: 1.5;
252   font-weight: bold;
253   width: 49%;
254   box-sizing: border-box; }
255 
256 .recharge-list .r-l-left ul {
257   margin: 0 12px;
258   -webkit-transition: -webkit-transform 0s ease-out;
259   -webkit-transform: translate3d(0, 0, 0); }
260 
261 .recharge-list .item {
262   border-top: 1px solid #ccc;
263   padding: 0 6px;
264   height: 42px;
265   line-height: 42px; }
266 
267 .recharge-list .item.current {
268   font-weight: bold;
269   font-size: 15px; }
270 
271 .recharge-list .item:first-child {
272   border: 0; }
273 
274 .top-cover,
275 .bottom-cover {
276   position: absolute;
277   left: 0;
278   width: 100%;
279   height: 22px;
280   text-indent: -999em;
281   background: #fff;
282   opacity: 0.5; }
283 
284 .top-cover {
285   top: 0; }
286 
287 .bottom-cover {
288   bottom: 0; }
289 
290 .skin-color {
291   font-weight: bold;
292   color: #f16b50; }
293 
294 @media screen and (max-width: 320px) {
295   .icon-lottery,
296   .icon-phone,
297   .icon-game,
298   .icon-qq,
299   .icon-hotel,
300   .icon-plane,
301   .icon-gas {
302     height: 80px;
303     background-size: 460px; }
304 
305   .icon-lottery {
306     background-position: 0 0;
307     width: 71px; }
308 
309   .icon-phone {
310     background-position: -71px 0;
311     width: 62px; }
312 
313   .icon-game {
314     background-position: -133px 0;
315     width: 73px; }
316 
317   .icon-qq {
318     background-position: -206px 0;
319     width: 66px; }
320 
321   .icon-hotel {
322     background-position: -271px 0;
323     width: 62px; }
324 
325   .icon-plane {
326     background-position: -333px 0;
327     width: 71px; }
328 
329   .icon-gas {
330     background-position: -406px 0;
331     width: 53px; } }
css 代码

 

HTML 结构部分:

 1 <!doctype html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8"/>
 5         <meta name="viewport" content="width=device-width, initial-scale=1,target-densitydpi=medium-dpi, user-scalable=no">
 6         <meta name="format-detection" content="telephone=no" />
 7         <title>充值首页 -- 手机充值</title>
 8         <link rel="stylesheet" href="css/index.css" />
 9     </head>
10     <body>
11         
12         <header class="header">
13             <h2 class="title">手机充值</h2><span class="icon-code-left"></span>
14         </header>
15         
16         <div class="wrapper recharge">
17             <div class="box-radius input-group">
18                 <label class="label">充值类型</label>
19                 <input class="input-control" placeholder="请输入手机号码"/>
20             </div>
21             <div class="box-radius input-group">
22                 <label class="label">充值面额</label>
23                 <div class="recharge-list clearfix">
24                     <div class="r-l-left">
25                         <s class="top-cover">top cover</s>
26                         <s class="bottom-cover">bottom cover</s>
27                         <div id="sliderEl" style="-webkit-transform: translate3d(0, 0, 0);"></div>
28                     </div>
29                     <div class="r-l-right">
30                         <span class="title">售价</span>
31                         <p class="price"><i id="showPriceEl"></i></p>
32                     </div>
33                 </div>
34             </div>
35             <div class="box-radius input-group">
36                 <label class="label">应付金额:<span class="skin-color"><i id="priceEl"></i></span></label>
37             </div>
38             <div class="btn-area"><em class="btn btn-large">立刻充值</em></div>
39         </div>
40         <script type="text/javascript" src="js/scroll-list.js"></script>
41         <script>
42         (function(){
43 
44             //调用
45             var data = [{id:"bm_50",showPrice:50,price:49.750},
46                         {id:"bm_30",showPrice:30,price:29.850},
47                         {id:"bm_100",showPrice:100,price:99.500},
48                         {id:"om_300",showPrice:300,price:298.500},
49                         {id:"om_500",showPrice:500,price:497.500}],
50                 el = document.getElementById('sliderEl');
51             
52             var slider = new Slider({
53                 dataModule     : data,
54                 sliderEl     : el,
55                 current     : 1,
56                 callBack     : function(data){
57                     if (!data) { return; }
58                     data.showPrice && (document.getElementById('showPriceEl').innerHTML = data.showPrice);
59                     data.price && (document.getElementById('priceEl').innerHTML = data.price);
60                 }
61             });
62             
63         })();
64         </script>
65     </body>
66 </html>
HTML 部分

 

Javascript 部分:

  1 var Slider;
  2 (function(){
  3 
  4     Slider = function(opt){
  5         this.el = opt.sliderEl;                //模板容器
  6         this.idx = opt.current;                //设定初始索引
  7         this.callBack = opt.callBack;
  8         
  9         this.dataIdx = [];                    //缓存索引数据
 10         this.dataModule = {};                //缓存数据对象
 11         this.setDataModule(opt.dataModule);
 12 
 13         //初始化
 14         this.init();
 15     };
 16     
 17     //数据处理
 18     Slider.prototype.setDataModule = function(data){
 19         if (!data) return;
 20         for (var i = 0, len = data.length; i < len; i++) {
 21             var d = data[i];
 22             if (!d) { continue; }
 23             this.dataIdx.push( d.id );
 24             this.dataModule[ d.id ] = d;
 25         }
 26     };
 27 
 28     Slider.prototype.init = function(){
 29         //渲染模板
 30         this.renderTpl();
 31 
 32         //设定滚动高度
 33         this.scaleH = this.el.getElementsByTagName('li')[0].clientHeight + 1; //1px border
 34         
 35         //初始总偏移量
 36         this.scrollY = 0;
 37         
 38         //绑定事件
 39         this.bindEvent();
 40 
 41     };
 42     
 43     //渲染模板
 44     Slider.prototype.renderTpl = function(){
 45         var data = this.dataIdx,
 46             el = this.el,
 47             dataArr = ['<ul>'];
 48         for (var i = 0, len = data.length; i < len; i++) {
 49             var id = data[i],
 50                 d = this.dataModule[id];
 51             if (!d) continue;
 52             dataArr.push( this.setTpl(d) );
 53         }
 54         dataArr.push('</ul>')
 55         el.innerHTML = dataArr.join('');
 56         
 57         //模板渲染完成后,设定初始选定项
 58         el.getElementsByTagName('li')[ this.idx ].className = 'item current';
 59         var cid = data[this.idx],
 60             cdata = this.dataModule[cid];
 61         this.callBack(cdata);
 62     };
 63     
 64     //普通list模板
 65     Slider.prototype.setTpl = function(data){
 66         return '<li class="item" data-val="'+ data.id +'">¥&nbsp;'+ data.showPrice +'</li>';
 67     };
 68     
 69 
 70     //绑定事件
 71     Slider.prototype.bindEvent = function(){
 72         
 73         var self = this,
 74             el = this.el,
 75 
 76             //手指按下
 77             startHandler = function(event){
 78                 //记录手指按下的坐标
 79                 self.startY = event.touches[0].pageY;
 80                 //清除偏移量
 81                 self.offsetY = 0;
 82                 //事件对象
 83                 self.target = event.target;
 84 
 85             },
 86             //手指移动
 87             moveHandler = function(event){
 88                 event.preventDefault();
 89 
 90                 //计算手指的偏移量
 91                 self.offsetY = event.targetTouches[0].pageY - self.startY;
 92 
 93                 //当前偏移量 + 总偏移量
 94                 var scrollHeight = self.offsetY + self.scrollY;
 95                 
 96                 el.style.webkitTransform = 'translate3d(0, '+ scrollHeight +'px, 0)';
 97                 
 98             },
 99             //手指抬起
100             endHandler = function(event){
101                 event.preventDefault();
102 
103                 //记录滑动边界,用于判定滑动的类型
104                 var boundary = self.scaleH / 2;
105 
106                 if (self.offsetY > boundary) {
107                     self.setIndex('-1');
108                 } else if (self.offsetY < 0 && self.offsetY < -boundary) {
109                     self.setIndex('+1');
110                 } else {
111                     self.setIndex('0');
112                 }
113 
114             };
115 
116             //绑定事件
117             el.addEventListener('touchstart', startHandler);
118             el.addEventListener('touchmove', moveHandler);
119             el.addEventListener('touchend', endHandler);
120     };
121 
122     //滑动
123     Slider.prototype.setIndex = function(n){
124         var el = this.el;
125 
126         //情景一:偏移量太小,偏移回原始位置即可
127         if (n == '0'){
128             el.style.webkitTransform = 'translate3d(0, '+ this.scrollY +'px, 0)';
129             return;
130         }
131 
132         //情景二:依照滚动的间距计算
133         var liEl = el.getElementsByTagName('li'),
134             liLen = liEl.length;
135         //在改变 this.idx 之前要去掉 当前 idx 的 current 状态
136         liEl[this.idx].className = 'item';
137 
138         var maxY = this.scaleH * -(liLen - 2),
139             minY = this.scaleH,
140             boundary = this.scaleH / 2,
141             d = Math.abs( this.offsetY % this.scaleH ), //取模 -- 偏移量
142             offIdx = Math.abs( this.offsetY / this.scaleH );        //取值 -- 偏移量
143         //四舍五入取 idx
144         if (d > boundary) {
145             offIdx = Math.ceil(offIdx);
146         } else {
147             offIdx = Math.floor(offIdx);
148         }
149         this.idx = this.idx + (n * offIdx); //重置 idx 索引
150         
151         if (n == '+1'){
152             scrollHeight = (-n * this.idx) * this.scaleH + (n * this.scaleH);
153         } else {
154             scrollHeight = (n * this.idx) * this.scaleH - (n * this.scaleH);
155         }
156         
157         if (this.idx < 0) { 
158             scrollHeight = minY;
159             this.idx = 0;
160         } else if (this.idx >= liLen) {
161             scrollHeight = maxY;
162             this.idx = liLen - 1;
163         }
164         
165         this.scrollY = scrollHeight;
166         
167         var li = liEl[this.idx],
168             cId = li.getAttribute('data-val'),
169             currentItemData = this.dataModule[cId];
170         li.className = 'item current';
171         
172         el.style.webkitTransform = 'translate3d(0, '+ scrollHeight +'px, 0)';
173         
174         this.callBack(currentItemData);
175     };
176     
177 })();

 

posted @ 2015-04-30 17:12  小菜38  阅读(2418)  评论(0编辑  收藏  举报