模拟滚动条

在工作中经常会遇到内容会超出固定的一个范围,超出的内容一般会使用到滚动条来滚动显示。

但是用浏览器默认的滚动条经常被产品经理鄙视,可是用css却改变不了滚动条的样式,还好,有万能的js ^_^~~

网上有各种各样的插件,但最顺手的还是自己写的,还可以一边撸一边当学习,自己动手丰衣足食  (*^__^*)

 

其中这三个问题深深地困扰我:

1、滚动条高度

2、每次点击向上、向下按钮的时候滚动条应该移动多少距离

3、每拖动1px滚动条,页面需要移动多少?

 

整个的框架大概是长这样的:

 

 

 

先来看看第一个问题。

  由于目前已经知道内容区域的高度和内容可视高度以及滚动条可滚动区域的高度了,由于内容区域与滚动条每次移动的距离都是成正比的,所以第一个问题很好解决:

  滚动条可移动范围 / 滚动条高度 = 内容高度 / 内容可视高度

 

每次点击按钮的时候滚动条应该移动多少距离?

  这里我是给参数distance设置一个值来决定每次点按钮的时候,内容区域应该滚动多少的距离。改变这个值可以改变内容区域滚动的快慢,如果有更好的处理方法和建议记得告诉我喔~

目前,内容区域每次滚动的距离是知道了,剩下的是计算滚动条相对于应该移动多少距离?

  滚动条可移动范围 /滚动条每次移动距离 = 内容区域高度 / 内容区域每次移动多少距离

 

效果如下:

 

 

这里还有一个问题,就是同时还得区分是单次点击还是长按。

所以得判断一下从按下按钮到松开时候的时长,目前设置为<100ms为单次点击,否则为长按:

 

 

拖动滚动条的时候,每移动1px滚动条,内容区域需要移动多少?

  先知道每1PX的距离占滚动条可移动范围的百分之几,再用内容区域高度除以所得的这个百分比,就得出滚动条每移动1px内容区域相对滚动多少距离了。

  内容区域滚动的距离 = 内容区域高度 / (滚动条滚动区域 / 1)

 

 

demo完整代码如下:

注意:

  因为用的是seajs写的,所以稍微留意下文件的加载情况啦

 

css:

1     .wapper{scrollbar-3dlight-color:#000; position:relative; height:302px;width:300px;overflow:hidden;margin:0 auto;line-height:40px;text-align:center;}
2     .area{background-color:#E2E2EF;width:100%; position:absolute;top:0px;left:0px;}
3     .bar{position:absolute;top:0px;right:0px; height:100%;width:1rem;background-color:#ccc;}
4     .scroll,.middle,.forward,.backward{display:block;cursor:pointer;position:absolute;right:0px;width:100%;}
5     .forward,.backward{height:16px;background-color:#6868B1;}
6     .middle{background-color:rgba(255, 255, 255, 0.22);top:16px;cursor:auto;}
7     .scroll{position:absolute;top:0px;background-color:#C2C2E9;}
8     .forward{top:0px;}
9     .backward{bottom:0px;}
View Code

 

html:

 1 <div class="wapper">
 2     <div class="area">
 3         <p>1、this is content</p>
 4         <p>2、this is content</p>
 5         <p>3、this is content</p>
 6         <p>4、this is content</p>
 7         <p>5、this is content</p>
 8         <p>6、this is content</p>
 9         <p>7、this is content</p>
10         <p>8、this is content</p>
11         <p>9、this is content</p>
12         <p>10、this is content</p>
13         <p>11、this is content</p>
14     </div>
15     <div class="bar">
16         <span class="forward"></span>
17         <span class="middle"><em class="scroll"></em></span>
18         <span class="backward"></span>
19     </div>
20 </div>
21 
22 <script type="text/javascript" src="../../lib/seajs/sea.js"></script>
23 <script type="text/javascript" src="../../lib/base/1.0.x/base.js"></script>
24 <script type="text/javascript">
25 seajs.use(['lib/jquery/1.11.x/index.js', '_example/simulationScroll/simulationScroll.js'], function($, scroll) {
26     scroll.init({
27         wapper: $('.wapper'),    
28         distance: 10,
29     });
30 });
View Code

 

js:

  1 //兼容PC移动移动端
  2 define(function(require, exports, module) {
  3 
  4     'use strict';
  5 
  6     var $ = require('lib/jquery/1.11.x/index.js');
  7 
  8     var parameter = null;
  9 
 10     //检测设备类型
 11     var startWhen, endWhen, moveWhen;
 12     var u = navigator.userAgent; 
 13 
 14     if ( u.match(/\b(Windows\sNT|Macintosh)\b/) ) {
 15         // 鼠标
 16         startWhen = 'mousedown';
 17         endWhen = 'mouseup';
 18         moveWhen = 'mousemove';
 19     } else {
 20         // 触摸屏
 21         startWhen = 'touchstart';
 22         endWhen = 'touchend';
 23         moveWhen = 'touchmove';
 24     }
 25 
 26     var simulation = {
 27 
 28         _mousedownTimer: 0,
 29         _setintervalId: 0,
 30         _longClick: false,    //是否长点击
 31         _turnOf: null,    //滚动方向
 32 
 33         init: function(options) {
 34 
 35             var t = this;
 36 
 37             t._scroll = $('.scroll'); //滚动条
 38 
 39             t._wapper = options.wapper.find('.area');    //内容区域
 40             t._distance = options.distance; //点击上下按钮页面每次滚动的距离
 41 
 42             var forward = $('.forward'),
 43                 middle = $('.middle'),
 44                 backward = $('.backward');
 45 
 46             parameter = {
 47                 view: t._wapper.parent().innerHeight(),    //视图高度
 48                 page: t._wapper.height(),    //内容高度
 49                 barArea: 0,    //滚动条可移动范围
 50                 scrollHeight: 0,    //滚动条的高度
 51                 scrollDistance: 0    //滚动条每次滚动的距离
 52             };
 53 
 54             //初始化滚动条
 55             if (parameter.page > parameter.view) {
 56 
 57                 //滚动条可移动范围
 58                 middle.height( parameter.view - forward.height() * 2);
 59 
 60                 parameter.barArea = middle.height();
 61 
 62                 //滚动条高度 = 滚动条可滚动范围 / (页面高度 / 可视高度)的百分比
 63                 parameter.scrollHeight = parameter.barArea / (parameter.page / parameter.view) ;
 64                 t._scroll.height(parameter.scrollHeight);
 65 
 66                 //滚动条每次滚动的距离 = 滚动条可移动范围 * 页面每次滚动的百分比
 67                 parameter.scrollDistance = parameter.barArea / (parameter.page / t._distance) ;
 68 
 69                 //拖动滚动条
 70                 t.liveEvent();
 71 
 72                 //点击向前按钮,如果按下鼠标到松开鼠标的时长<100ms,则为单次点击
 73                 forward.bind(startWhen, function(e){
 74 
 75                     t._turnOf = 'forward';
 76 
 77                     t.longPress(e, t.direction );
 78 
 79                 }).bind(endWhen, function(e) { 
 80 
 81                     t.mouseupFun(e, t.direction);
 82 
 83                     t._turnOf = null;
 84 
 85                 });
 86 
 87                 //点击向后按钮
 88                 backward.bind(startWhen, function(e){
 89 
 90                     t._turnOf = null;
 91 
 92                     t.longPress(e, t.direction );
 93 
 94                 }).bind(endWhen, function(e){
 95 
 96                     t.mouseupFun(e, t.direction );
 97 
 98                 });
 99 
100                 //注册鼠标滚动事件
101                 // FF
102                 if(document.addEventListener){
103                     document.addEventListener('DOMMouseScroll',t.mouseRuning,false);
104                 }
105 
106                 //其它浏览器
107                 document.onmousewheel = t.mouseRuning;
108             }
109         },
110 
111         //鼠标滚动
112         mouseRuning: function(e) {
113 
114             e = e || window.event;
115             var t = simulation;
116             var detail = e.detail || e.wheelDelta;
117 
118             switch(true){
119                 case detail>=100:
120                 case detail<=0 && detail>=-100:
121                     t._turnOf = 'forward';
122                     
123                 break;
124                 
125                 case detail<=-100:
126                 case detail>0 && detail<=100:
127                     t._turnOf = null;
128                 break;
129             }
130 
131             t.direction ();
132         },
133 
134         //判断是否长点击
135         longPress: function(e, moveFun ) {
136 
137             var t = this;
138 
139             if ( u.match(/\b(Windows\sNT|Macintosh)\b/) ) {
140                 e = e || window.event;
141 
142                 // 限制为鼠标左键点击才触发
143                 if (/^mouse/.test(e.type) && e.which !== 1) {
144                     return;
145                 }
146             }
147 
148             t._setintervalId = setInterval(function(){
149 
150                 t._mousedownTimer += 10;
151 
152                 if( t._mousedownTimer >= 100 ){
153 
154                     moveFun();
155                 }
156 
157             },20);
158         },
159 
160         mouseupFun: function(e, moveFun) {
161             
162             var t = this;
163 
164             if ( u.match(/\b(Windows\sNT|Macintosh)\b/) ) {
165                 e = e || window.event;
166 
167                 // 限制为鼠标左键点击才触发
168                 if (/^mouse/.test(e.type) && e.which !== 1) {
169                     return;
170                 }
171             }
172 
173             clearTimeout(t._setintervalId);
174 
175             if( t._mousedownTimer < 100 ) {
176 
177                 moveFun();
178             }
179 
180             t._mousedownTimer = 0;
181         },
182 
183         direction:function() {
184             var t = simulation,
185                 barTop = t._scroll.position().top,
186                 pageTop = t._wapper.position().top,
187                 moveDistance = {};
188 
189                 if ( t._turnOf === 'forward') {
190 
191                     //页面到顶,不执行任何操作
192                     if (barTop < 0) {
193 
194                         return;
195                     }
196 
197                     moveDistance = {
198                         page: pageTop + t._distance,
199                         bar: barTop - parameter.scrollDistance
200                     }
201 
202                     //如果滚动条距离顶部的距离少 < 每次滚动的距离,或者已经滚动到顶部,则不再滚动
203                     if(barTop < parameter.scrollDistance || barTop <= 0){
204 
205                         moveDistance = {
206                             page: 0,
207                             bar: 0
208                         }
209                     }
210                 } else {
211 
212                     //页面到底,不执行任何操作
213                     if (barTop == parameter.barArea - parameter.scrollHeight){
214                         return;
215                     }
216 
217                     moveDistance = {
218                         page: pageTop - t._distance,
219                         bar: barTop + parameter.scrollDistance
220                     };
221 
222                     // 如果滚动条距离底部的距离值 < 每次滚动的距离 或者已经到底部,则一次滚到底
223                     if ( moveDistance.bar + parameter.scrollHeight >= parameter.barArea) {
224 
225                         moveDistance = {
226                             page: parameter.view - parameter.page,
227                             bar: parameter.barArea - parameter.scrollHeight
228                         };
229 
230                     }
231                 }
232 
233                 t._scroll.css({top: moveDistance.bar});
234                 t._wapper.css({top: moveDistance.page});    
235         },
236 
237         //拖动滚动条
238         liveEvent: function() {
239             var t = this,
240                 draging = false,
241                 currentY = 0,
242                 lastY = 0,
243                 pageY = 0;    
244 
245             //检测设备类型
246             var _ua = function(e) {
247 
248                 var Pos = null;
249 
250                 if ( u.match(/\b(Windows\sNT|Macintosh)\b/) ) {
251                     e = e || window.event;
252 
253                     // 限制为鼠标左键点击才触发
254                     if (/^mouse/.test(e.type) && e.which !== 1) {
255                         return;
256                     }
257 
258                     Pos = {
259                         left : e.pageX,
260                         top: e.pageY
261                     }
262 
263                 } else {
264                     Pos = {
265                         left : e.originalEvent.targetTouches[0].pageX,
266                         top: e.originalEvent.targetTouches[0].pageY
267                     }
268                 }
269                 return Pos;
270             };
271 
272             var _start = function(e) {
273 
274                 //监控鼠标
275                 e.preventDefault();
276 
277                 if (t._scroll.get(0).setCapture) {
278                     t._scroll.get(0).setCapture();
279                 }
280 
281                 draging = true;
282 
283                 //记录当前滚动条的坐标
284                 lastY = t._scroll.position().top; 
285 
286                 //记录按下鼠标的坐标
287                 pageY = _ua(e).top;
288             };
289 
290             var _drag = function(e) {
291 
292                 if( draging ) {
293 
294                     var pageTop = t._wapper.position().top;
295                     var barTop = t._scroll.position().top;
296 
297                     //滚动条每移动1px,页面相对滚动Npx 再 * 当前滚动条的到顶部的距离
298                     var pageMoveDistance = -(parameter.page / (parameter.barArea / 1)) * barTop;
299 
300                     if (lastY + ( _ua(e).top - pageY ) < 0) {
301                         currentY = 0;
302                         pageMoveDistance = 0;
303 
304                     } else if( lastY + ( _ua(e).top - pageY) + parameter.scrollHeight >= parameter.barArea) {
305                         currentY = parameter.barArea - parameter.scrollHeight;
306                         pageMoveDistance = parameter.view - parameter.page;
307                     }
308                     else {
309                         currentY = lastY + ( _ua(e).top - pageY);
310                     }
311 
312                     t._scroll.css({ top:currentY});
313                     t._wapper.css({top: pageMoveDistance});    
314                 }
315             };
316 
317             var _end = function(e) {
318 
319                 if (draging) {
320 
321                     draging = false;
322 
323                     //在IE下释放对鼠标的控制
324                     if (t._scroll.get(0).setCapture) {
325                         t._scroll.get(0).releaseCapture();
326                     }
327                     
328                     document.onmousemove = null;
329                     document.onmouseup = null;
330                 }
331             };
332 
333             t._scroll.bind( startWhen, _start );
334 
335             t._wapper.bind( startWhen, _start );
336 
337             $(document).bind( moveWhen, _drag );
338            
339             $(document).bind( endWhen, _end );
340 
341             $(document).bind('blur', _end);
342         }
343     }
344     return simulation;
345 });
View Code

 

posted @ 2016-02-01 13:25  带上饼干  阅读(1373)  评论(6编辑  收藏  举报