hjg
2024-10-30 8cf23534166c07e711aac2a25911ada317ba01f0
提交 | 用户 | 时间
58d006 1 /*! Copyright (c) 2011 Piotr Rochala (http://rocha.la)
A 2  * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
3  * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
4  *
5  * Version: 1.3.1
6  *
7  */
8 (function($) {
9
10   jQuery.fn.extend({
11     slimScroll: function(options) {
12
13       var defaults = {
14
15         // width in pixels of the visible scroll area
16         width : 'auto',
17
18         // height in pixels of the visible scroll area
19         height : '250px',
20
21         // width in pixels of the scrollbar and rail
22         size : '7px',
23
24         // scrollbar color, accepts any hex/color value
25         color: '#000',
26
27         // scrollbar position - left/right
28         position : 'right',
29
30         // distance in pixels between the side edge and the scrollbar
31         distance : '1px',
32
33         // default scroll position on load - top / bottom / $('selector')
34         start : 'top',
35
36         // sets scrollbar opacity
37         opacity : .4,
38
39         // enables always-on mode for the scrollbar
40         alwaysVisible : false,
41
42         // check if we should hide the scrollbar when user is hovering over
43         disableFadeOut : false,
44
45         // sets visibility of the rail
46         railVisible : false,
47
48         // sets rail color
49         railColor : '#333',
50
51         // sets rail opacity
52         railOpacity : .2,
53
54         // whether  we should use jQuery UI Draggable to enable bar dragging
55         railDraggable : true,
56
57         // defautlt CSS class of the slimscroll rail
58         railClass : 'slimScrollRail',
59
60         // defautlt CSS class of the slimscroll bar
61         barClass : 'slimScrollBar',
62
63         // defautlt CSS class of the slimscroll wrapper
64         wrapperClass : 'slimScrollDiv',
65
66         // check if mousewheel should scroll the window if we reach top/bottom
67         allowPageScroll : false,
68
69         // scroll amount applied to each mouse wheel step
70         wheelStep : 20,
71
72         // scroll amount applied when user is using gestures
73         touchScrollStep : 200,
74
75         // sets border radius
76         borderRadius: '7px',
77
78         // sets border radius of the rail
79         railBorderRadius : '7px'
80       };
81
82       var o = $.extend(defaults, options);
83
84       // do it for every element that matches selector
85       this.each(function(){
86
87       var isOverPanel, isOverBar, isDragg, queueHide, touchDif,
88         barHeight, percentScroll, lastScroll,
89         divS = '<div></div>',
90         minBarHeight = 30,
91         releaseScroll = false;
92
93         // used in event handlers and for better minification
94         var me = $(this);
95
96         // ensure we are not binding it again
97         if (me.parent().hasClass(o.wrapperClass))
98         {
99             // start from last bar position
100             var offset = me.scrollTop();
101
102             // find bar and rail
103             bar = me.parent().find('.' + o.barClass);
104             rail = me.parent().find('.' + o.railClass);
105
106             getBarHeight();
107
108             // check if we should scroll existing instance
109             if ($.isPlainObject(options))
110             {
111               // Pass height: auto to an existing slimscroll object to force a resize after contents have changed
112               if ( 'height' in options && options.height == 'auto' ) {
113                 me.parent().css('height', 'auto');
114                 me.css('height', 'auto');
115                 var height = me.parent().parent().height();
116                 me.parent().css('height', height);
117                 me.css('height', height);
118               }
119
120               if ('scrollTo' in options)
121               {
122                 // jump to a static point
123                 offset = parseInt(o.scrollTo);
124               }
125               else if ('scrollBy' in options)
126               {
127                 // jump by value pixels
128                 offset += parseInt(o.scrollBy);
129               }
130               else if ('destroy' in options)
131               {
132                 // remove slimscroll elements
133                 bar.remove();
134                 rail.remove();
135                 me.unwrap();
136                 return;
137               }
138
139               // scroll content by the given offset
140               scrollContent(offset, false, true);
141             }
142
143             return;
144         }
145
146         // optionally set height to the parent's height
147         o.height = (o.height == 'auto') ? me.parent().height() : o.height;
148
149         // wrap content
150         var wrapper = $(divS)
151           .addClass(o.wrapperClass)
152           .css({
153             position: 'relative',
154             overflow: 'hidden',
155             width: o.width,
156             height: o.height
157           });
158
159         // update style for the div
160         me.css({
161           overflow: 'hidden',
162           width: o.width,
163           height: o.height
164         });
165
166         // create scrollbar rail
167         var rail = $(divS)
168           .addClass(o.railClass)
169           .css({
170             width: o.size,
171             height: '100%',
172             position: 'absolute',
173             top: 0,
174             display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none',
175             'border-radius': o.railBorderRadius,
176             background: o.railColor,
177             opacity: o.railOpacity,
178             zIndex: 90
179           });
180
181         // create scrollbar
182         var bar = $(divS)
183           .addClass(o.barClass)
184           .css({
185             background: o.color,
186             width: o.size,
187             position: 'absolute',
188             top: 0,
189             opacity: o.opacity,
190             display: o.alwaysVisible ? 'block' : 'none',
191             'border-radius' : o.borderRadius,
192             BorderRadius: o.borderRadius,
193             MozBorderRadius: o.borderRadius,
194             WebkitBorderRadius: o.borderRadius,
195             zIndex: 99
196           });
197
198         // set position
199         var posCss = (o.position == 'right') ? { right: o.distance } : { left: o.distance };
200         rail.css(posCss);
201         bar.css(posCss);
202
203         // wrap it
204         me.wrap(wrapper);
205
206         // append to parent div
207         me.parent().append(bar);
208         me.parent().append(rail);
209
210         // make it draggable and no longer dependent on the jqueryUI
211         if (o.railDraggable){
212           bar.bind("mousedown", function(e) {
213             var $doc = $(document);
214             isDragg = true;
215             t = parseFloat(bar.css('top'));
216             pageY = e.pageY;
217
218             $doc.bind("mousemove.slimscroll", function(e){
219               currTop = t + e.pageY - pageY;
220               bar.css('top', currTop);
221               scrollContent(0, bar.position().top, false);// scroll content
222             });
223
224             $doc.bind("mouseup.slimscroll", function(e) {
225               isDragg = false;hideBar();
226               $doc.unbind('.slimscroll');
227             });
228             return false;
229           }).bind("selectstart.slimscroll", function(e){
230             e.stopPropagation();
231             e.preventDefault();
232             return false;
233           });
234         }
235
236         // on rail over
237         rail.hover(function(){
238           showBar();
239         }, function(){
240           hideBar();
241         });
242
243         // on bar over
244         bar.hover(function(){
245           isOverBar = true;
246         }, function(){
247           isOverBar = false;
248         });
249
250         // show on parent mouseover
251         me.hover(function(){
252           isOverPanel = true;
253           showBar();
254           hideBar();
255         }, function(){
256           isOverPanel = false;
257           hideBar();
258         });
259
260         // support for mobile
261         me.bind('touchstart', function(e,b){
262           if (e.originalEvent.touches.length)
263           {
264             // record where touch started
265             touchDif = e.originalEvent.touches[0].pageY;
266           }
267         });
268
269         me.bind('touchmove', function(e){
270           // prevent scrolling the page if necessary
271           if(!releaseScroll)
272           {
273                 e.originalEvent.preventDefault();
274               }
275           if (e.originalEvent.touches.length)
276           {
277             // see how far user swiped
278             var diff = (touchDif - e.originalEvent.touches[0].pageY) / o.touchScrollStep;
279             // scroll content
280             scrollContent(diff, true);
281             touchDif = e.originalEvent.touches[0].pageY;
282           }
283         });
284
285         // set up initial height
286         getBarHeight();
287
288         // check start position
289         if (o.start === 'bottom')
290         {
291           // scroll content to bottom
292           bar.css({ top: me.outerHeight() - bar.outerHeight() });
293           scrollContent(0, true);
294         }
295         else if (o.start !== 'top')
296         {
297           // assume jQuery selector
298           scrollContent($(o.start).position().top, null, true);
299
300           // make sure bar stays hidden
301           if (!o.alwaysVisible) { bar.hide(); }
302         }
303
304         // attach scroll events
305         attachWheel();
306
307         function _onWheel(e)
308         {
309           // use mouse wheel only when mouse is over
310           if (!isOverPanel) { return; }
311
312           var e = e || window.event;
313
314           var delta = 0;
315           if (e.wheelDelta) { delta = -e.wheelDelta/120; }
316           if (e.detail) { delta = e.detail / 3; }
317
318           var target = e.target || e.srcTarget || e.srcElement;
319           if ($(target).closest('.' + o.wrapperClass).is(me.parent())) {
320             // scroll content
321             scrollContent(delta, true);
322           }
323
324           // stop window scroll
325           if (e.preventDefault && !releaseScroll) { e.preventDefault(); }
326           if (!releaseScroll) { e.returnValue = false; }
327         }
328
329         function scrollContent(y, isWheel, isJump)
330         {
331           releaseScroll = false;
332           var delta = y;
333           var maxTop = me.outerHeight() - bar.outerHeight();
334
335           if (isWheel)
336           {
337             // move bar with mouse wheel
338             delta = parseInt(bar.css('top')) + y * parseInt(o.wheelStep) / 100 * bar.outerHeight();
339
340             // move bar, make sure it doesn't go out
341             delta = Math.min(Math.max(delta, 0), maxTop);
342
343             // if scrolling down, make sure a fractional change to the
344             // scroll position isn't rounded away when the scrollbar's CSS is set
345             // this flooring of delta would happened automatically when
346             // bar.css is set below, but we floor here for clarity
347             delta = (y > 0) ? Math.ceil(delta) : Math.floor(delta);
348
349             // scroll the scrollbar
350             bar.css({ top: delta + 'px' });
351           }
352
353           // calculate actual scroll amount
354           percentScroll = parseInt(bar.css('top')) / (me.outerHeight() - bar.outerHeight());
355           delta = percentScroll * (me[0].scrollHeight - me.outerHeight());
356
357           if (isJump)
358           {
359             delta = y;
360             var offsetTop = delta / me[0].scrollHeight * me.outerHeight();
361             offsetTop = Math.min(Math.max(offsetTop, 0), maxTop);
362             bar.css({ top: offsetTop + 'px' });
363           }
364
365           // scroll content
366           me.scrollTop(delta);
367
368           // fire scrolling event
369           me.trigger('slimscrolling', ~~delta);
370
371           // ensure bar is visible
372           showBar();
373
374           // trigger hide when scroll is stopped
375           hideBar();
376         }
377
378         function attachWheel()
379         {
380           if (window.addEventListener)
381           {
382             this.addEventListener('DOMMouseScroll', _onWheel, false );
383             this.addEventListener('mousewheel', _onWheel, false );
384             this.addEventListener('MozMousePixelScroll', _onWheel, false );
385           }
386           else
387           {
388             document.attachEvent("onmousewheel", _onWheel)
389           }
390         }
391
392         function getBarHeight()
393         {
394           // calculate scrollbar height and make sure it is not too small
395           barHeight = Math.max((me.outerHeight() / me[0].scrollHeight) * me.outerHeight(), minBarHeight);
396           bar.css({ height: barHeight + 'px' });
397
398           // hide scrollbar if content is not long enough
399           var display = barHeight == me.outerHeight() ? 'none' : 'block';
400           bar.css({ display: display });
401         }
402
403         function showBar()
404         {
405           // recalculate bar height
406           getBarHeight();
407           clearTimeout(queueHide);
408
409           // when bar reached top or bottom
410           if (percentScroll == ~~percentScroll)
411           {
412             //release wheel
413             releaseScroll = o.allowPageScroll;
414
415             // publish approporiate event
416             if (lastScroll != percentScroll)
417             {
418                 var msg = (~~percentScroll == 0) ? 'top' : 'bottom';
419                 me.trigger('slimscroll', msg);
420             }
421           }
422           else
423           {
424             releaseScroll = false;
425           }
426           lastScroll = percentScroll;
427
428           // show only when required
429           if(barHeight >= me.outerHeight()) {
430             //allow window scroll
431             releaseScroll = true;
432             return;
433           }
434           bar.stop(true,true).fadeIn('fast');
435           if (o.railVisible) { rail.stop(true,true).fadeIn('fast'); }
436         }
437
438         function hideBar()
439         {
440           // only hide when options allow it
441           if (!o.alwaysVisible)
442           {
443             queueHide = setTimeout(function(){
444               if (!(o.disableFadeOut && isOverPanel) && !isOverBar && !isDragg)
445               {
446                 bar.fadeOut('slow');
447                 rail.fadeOut('slow');
448               }
449             }, 1000);
450           }
451         }
452
453       });
454
455       // maintain chainability
456       return this;
457     }
458   });
459
460   jQuery.fn.extend({
461     slimscroll: jQuery.fn.slimScroll
462   });
463
464 })(jQuery);