├── gulpfile.js
├── bower.json
├── package.json
├── .gitignore
├── README.md
├── dist
├── k-scroll.css
└── k-scroll.js
└── src
├── k-scroll.css
└── k-scroll.js
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 |
3 | var uglify = require('gulp-uglify');
4 | var minifyCSS = require('gulp-minify-css');
5 |
6 | gulp.task('default', function () {
7 | gulp.src('./src/k-scroll.js')
8 | .pipe(uglify())
9 | .pipe(gulp.dest('./dist/'));
10 |
11 | gulp.src('./src/k-scroll.css')
12 | .pipe(minifyCSS())
13 | .pipe(gulp.dest('./dist/'));
14 | });
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "k-scroll",
3 | "version": "0.0.1",
4 | "homepage": "https://github.com/kuroguo/k-scroll",
5 | "authors": [
6 | "KuroGuo <413298956@qq.com>"
7 | ],
8 | "description": "High performance scroll component.",
9 | "main": "dist/k-scroll.js",
10 | "keywords": [
11 | "k-scroll",
12 | "kuro"
13 | ],
14 | "license": "MIT",
15 | "ignore": [
16 | "**/.*",
17 | "node_modules",
18 | "bower_components",
19 | "test",
20 | "tests"
21 | ],
22 | "dependencies": {
23 | "k-drag": "*",
24 | "velocity": "~1.2.1"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "k-scroll",
3 | "version": "0.0.1",
4 | "description": "High performance scroll component.",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/kuroguo/k-scroll"
8 | },
9 | "keywords": [
10 | "k-scroll",
11 | "kuro"
12 | ],
13 | "author": "kuro",
14 | "license": "MIT",
15 | "bugs": {
16 | "url": "https://github.com/kuroguo/k-scroll/issues"
17 | },
18 | "homepage": "https://github.com/kuroguo/k-scroll",
19 | "devDependencies": {
20 | "gulp": "^3.8.10",
21 | "gulp-minify-css": "^0.3.13",
22 | "gulp-uglify": "^1.1.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # Compiled binary addons (http://nodejs.org/api/addons.html)
20 | build/Release
21 |
22 | # Dependency directory
23 | # Commenting this out is preferred by some people, see
24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
25 | node_modules
26 |
27 | # Users Environment Variables
28 | .lock-wscript
29 |
30 | bower_components
31 |
32 | .sass-cache
33 |
34 | /example
35 |
36 | /static/stylesheets/temp
37 |
38 | /config.js
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## K-Scroll
2 |
3 | High performance scroll component.
4 |
5 | ### Install
6 |
7 | ```bash
8 | $ bower install k-scroll
9 | ```
10 |
11 | ### Quick Example
12 |
13 | example
14 |
15 | ```html
16 |
17 |
26 |
27 |
28 |
29 |
30 |
43 | ```
44 |
--------------------------------------------------------------------------------
/dist/k-scroll.css:
--------------------------------------------------------------------------------
1 | .k-scroller-wrapper>.scroll-bar{-webkit-transition-property:border-right-width,opacity;-moz-transition-property:border-right-width,opacity;transition-property:border-right-width,opacity;-webkit-transition-duration:.2s,.2s;-moz-transition-duration:.2s,.2s;transition-duration:.2s,.2s;-webkit-transition-delay:.4s,1s;-moz-transition-delay:.4s,1s;transition-delay:.4s,1s;position:absolute;right:0;top:0;width:1rem;height:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;z-index:100;border-width:0 .3rem 0 .2rem;border-style:solid;border-left-color:transparent;border-right-color:rgba(0,0,0,.3);opacity:0}.k-scroller-wrapper.hover>.scroll-bar{opacity:1;-webkit-transition-duration:.2s,.2s;-moz-transition-duration:.2s,.2s;transition-duration:.2s,.2s;-webkit-transition-delay:.4s,0;-moz-transition-delay:.4s,0;transition-delay:.4s,0}.k-scroller-wrapper.dragging>.scroll-bar,.k-scroller-wrapper.scrolling>.scroll-bar,.k-scroller-wrapper.sliding>.scroll-bar{opacity:1;-webkit-transition-duration:.2s,0;-moz-transition-duration:.2s,0;transition-duration:.2s,0;-webkit-transition-delay:0,0;-moz-transition-delay:0,0;transition-delay:0,0}.k-scroller-wrapper>.scroll-bar.dragging,.k-scroller-wrapper>.scroll-bar.hover{opacity:1;border-right-width:.8rem;-webkit-transition-duration:.2s,0;-moz-transition-duration:.2s,0;transition-duration:.2s,0;-webkit-transition-delay:0,0;-moz-transition-delay:0,0;transition-delay:0,0}.k-scroller-wrapper>.scroll-bar.active,.k-scroller-wrapper>.scroll-bar.dragging{border-right-color:rgba(0,0,0,.4)}
--------------------------------------------------------------------------------
/src/k-scroll.css:
--------------------------------------------------------------------------------
1 | .k-scroller-wrapper > .scroll-bar {
2 | -webkit-transition-property: border-right-width, opacity;
3 | -moz-transition-property: border-right-width, opacity;
4 | transition-property: border-right-width, opacity;
5 | -webkit-transition-duration: .2s, .2s;
6 | -moz-transition-duration: .2s, .2s;
7 | transition-duration: .2s, .2s;
8 | -webkit-transition-delay: .4s, 1s;
9 | -moz-transition-delay: .4s, 1s;
10 | transition-delay: .4s, 1s;
11 | position: absolute;
12 | right: 0;
13 | top: 0;
14 | width: 1rem;
15 | height: 0;
16 | -webkit-box-sizing:border-box;
17 | -moz-box-sizing:border-box;
18 | box-sizing:border-box;
19 | z-index: 100;
20 | border-width: 0;
21 | border-style: solid;
22 | border-left-width: .2rem;
23 | border-left-color: transparent;
24 | border-right-color: rgba(0, 0, 0, .3);
25 | border-right-width: .3rem;
26 | opacity: 0;
27 | }
28 |
29 | .k-scroller-wrapper.hover > .scroll-bar {
30 | opacity: 1;
31 | -webkit-transition-duration: .2s, .2s;
32 | -moz-transition-duration: .2s, .2s;
33 | transition-duration: .2s, .2s;
34 | -webkit-transition-delay: .4s, 0;
35 | -moz-transition-delay: .4s, 0;
36 | transition-delay: .4s, 0;
37 | }
38 |
39 | .k-scroller-wrapper.dragging > .scroll-bar,
40 | .k-scroller-wrapper.scrolling > .scroll-bar,
41 | .k-scroller-wrapper.sliding > .scroll-bar {
42 | opacity: 1;
43 | -webkit-transition-duration: .2s, 0;
44 | -moz-transition-duration: .2s, 0;
45 | transition-duration: .2s, 0;
46 | -webkit-transition-delay: 0, 0;
47 | -moz-transition-delay: 0, 0;
48 | transition-delay: 0, 0;
49 | }
50 |
51 | .k-scroller-wrapper > .scroll-bar.hover,
52 | .k-scroller-wrapper > .scroll-bar.dragging {
53 | opacity: 1;
54 | border-right-width: .8rem;
55 | -webkit-transition-duration: .2s, 0;
56 | -moz-transition-duration: .2s, 0;
57 | transition-duration: .2s, 0;
58 | -webkit-transition-delay: 0, 0;
59 | -moz-transition-delay: 0, 0;
60 | transition-delay: 0, 0;
61 | }
62 |
63 | .k-scroller-wrapper > .scroll-bar.active,
64 | .k-scroller-wrapper > .scroll-bar.dragging {
65 | border-right-color: rgba(0, 0, 0, .4);
66 | }
--------------------------------------------------------------------------------
/dist/k-scroll.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"use strict";function n(e){return e.wheelDelta?e.wheelDelta/120:-(e.detail||0)/3}var r={};r.bind=function(r,a){function s(){Q.unbind(),U.unbind(),B.removeEventListener("mouseenter",T),B.removeEventListener("mousedown",T),B.removeEventListener("touchstart",T),B.removeEventListener("mouseenter",m),B.removeEventListener("mouseleave",L),B.removeEventListener("mousedown",D),B.removeEventListener("touchstart",D),e.removeEventListener("blur",D),B.removeEventListener("mousewheel",y),B.removeEventListener("touchstart",g),B.removeEventListener("mousedown",g),B.removeEventListener("k.dragstart",E),B.removeEventListener("k.drag",p),B.removeEventListener("touchend",f),B.removeEventListener("mouseup",f),B.removeEventListener("k.dragend",h),G.removeEventListener("mouseenter",o),G.removeEventListener("mouseleave",i),G.removeEventListener("touchstart",d),G.removeEventListener("mousedown",d),G.removeEventListener("touchend",c),G.removeEventListener("touchcancel",c),G.removeEventListener("k.dragstart",v),G.removeEventListener("k.drag",u),G.removeEventListener("k.dragend",l),e.removeEventListener("resize",w),t.removeEventListener("keydown",b)}function o(e){var t=e.currentTarget;t.classList.add("hover")}function i(e){var t=e.currentTarget;t.classList.remove("hover")}function d(e){e.preventDefault();var n=e.currentTarget;n.classList.add("active"),"mousedown"===e.type&&t.addEventListener("mouseup",c,!0)}function c(e){G.classList.remove("active"),"mouseup"===e.type&&t.removeEventListener("mouseup",c,!0)}function u(e){var t=A+e.deltaY*(C-F)/(F-K);t>q?t=q:H>t&&(t=H),V(t,!1,!1)}function v(e){var t=e.currentTarget;T(),A=I,t.classList.add("dragging")}function l(e){var t=e.currentTarget;t.classList.remove("dragging")}function m(e){x();var t=e.currentTarget;t.classList.add("hover")}function L(e){var t=e.currentTarget;t.classList.remove("hover")}function g(e){Z=!1,"mousedown"===e.type?Y.allowMouseDragScroll&&e.preventDefault():e.preventDefault()}function f(e){var t=e.currentTarget;Z||(R=0,j=null,t.classList.add("sliding"),M())}function E(e){if(!e.dragTarget.classList.contains("scroll-bar")){if(!Y.allowMouseDragScroll&&"mouse"===e.pointerType&&!e.ctrlKey)return void e.prevent();var t=e.currentTarget;e.state>0&&(t.classList.add("dragging"),Z=!0)}}function p(e){e.dragTarget.classList.contains("scroll-bar")||(I>q?e.vy<=0&&(e.stepY/=1+Math.abs(I-q)/14):H>I&&e.vy>=0&&(e.stepY/=1+Math.abs(I-H)/14),J=-e.vy,I-=e.stepY,V(I,!1,!1))}function h(e){if(!e.dragTarget.classList.contains("scroll-bar")){var t=e.currentTarget;t.classList.remove("dragging"),R=J=-e.vy,j=null,t.classList.add("sliding"),M()}}function y(e){if(!e.ctrlKey){T(),e.preventDefault();var t=n(e),r=I-t*Y.speed;r>q?r=q:H>r&&(r=H),J=0,V(r,!0,!0)}}function k(e){for(var t in e)void 0!==e[t]&&(Y[t]=e[t])}function b(e){if(Y.bindKey){switch(e.keyCode){case 33:I-=F-3;break;case 34:I+=F-3;break;case 38:I-=Y.speed;break;case 40:I+=Y.speed;break;default:return}T(),H>I?I=H:I>q&&(I=q),V(I,!0,!0)}}function w(){Y.checkOnResize&&"none"!==B.style.display&&(T(),I>q&&V(q))}function D(e){O&&(S(),"blur"!==e.type&&Math.abs(J)>.14&&(e.stopPropagation(),e.preventDefault())),J=0,B.classList.remove("sliding"),e.ctrlKey&&"mousedown"===e.type&&e.preventDefault()}function T(){var t=e.getComputedStyle(B),n=e.getComputedStyle(P);F=parseFloat(t.height),C=parseFloat(n.height),q=Math.max(0,C-F),z=F/C,z>=1&&(z=0),K=Math.max(F*z,56)}function M(t){var n,r,a;j&&(n=t-j,a=J*Math.pow(.95,n/(1e3/60)),r=I+(J+a)/2*n,V(r,!1,!1),J=a,I>q?0>=J?(J=(q-I)/200,0>R&&J>R?J=R:J>-.03&&(J=-.03)):(J-=3e-4*(I-q)*n,0>J&&(J=0)):H>I&&(J>=0?(J=(H-I)/200,R>0&&R>J?J=R:.03>J&&(J=.03)):(J-=3e-4*(I-H)*n,J>0&&(J=0)))),j=t,Math.abs(I-q)<.03?I=q:Math.abs(I-H)<.03&&(I=H),!B.classList.contains("dragging")&&(Math.abs(J)>.03||I>q||H>I)?O=e.requestAnimationFrame(M):(J=0,B.classList.remove("sliding"),e.cancelAnimationFrame(O),O=null)}function x(e){var t=I/(C-F);G.display=0>=z?"none":"block",Velocity.hook(G,"height",K+"px"),Velocity(G,"stop");var n=(F-K)*t+"px";e?Velocity(G,{translateY:n},{duration:Y.animationDuration,easing:Y.animationEasing}):Velocity.hook(G,"translateY",n)}function V(e,t,n,r,a){I=e,S(),t?Velocity(P,{translateY:-I+"px"},{duration:r||Y.animationDuration,easing:Y.animationEasing,begin:function(){B.classList.add("scrolling")},complete:function(){B.classList.remove("scrolling"),"function"==typeof a&&a.call(this)}}):(Velocity.hook(P,"translateY",-I+"px"),"function"==typeof a&&a.call(this)),x(n)}function S(){e.cancelAnimationFrame(O),O=null,Velocity(P,"stop")}var Y={animationDuration:200,animationEasing:[0,0,.58,1],speed:100,allowMouseDragScroll:!0,checkOnResize:!0,bindKey:!0};k(a);var C,F,K,q,z,A,j,O,R,Z,B=r,P=B.querySelector(".k-scroller"),G=t.createElement("span"),H=0,I=0,J=0;G.classList.add("scroll-bar"),B.appendChild(G);var N;"function"==typeof require?N=require("kDrag"):e.kDrag&&(N=e.kDrag);var Q=N.bind(B),U=N.bind(G);return B.addEventListener("mouseenter",T),B.addEventListener("mousedown",T),B.addEventListener("touchstart",T),B.addEventListener("mouseenter",m),B.addEventListener("mouseleave",L),B.addEventListener("mousedown",D),B.addEventListener("touchstart",D),e.addEventListener("blur",D),B.addEventListener("mousewheel",y),B.addEventListener("touchstart",g),B.addEventListener("mousedown",g),B.addEventListener("k.dragstart",E),B.addEventListener("k.drag",p),B.addEventListener("touchend",f),B.addEventListener("mouseup",f),B.addEventListener("k.dragend",h),G.addEventListener("mouseenter",o),G.addEventListener("mouseleave",i),G.addEventListener("touchstart",d),G.addEventListener("mousedown",d),G.addEventListener("touchend",c),G.addEventListener("touchcancel",c),G.addEventListener("k.dragstart",v),G.addEventListener("k.drag",u),G.addEventListener("k.dragend",l),e.addEventListener("resize",w),t.addEventListener("keydown",b),Velocity.hook(P,"translateZ","0.00001px"),Velocity.hook(G,"translateZ","0.00001px"),V(I,!1,!1),{unbind:s,configure:k,scrollTo:V,stopAnimation:S,refreshContext:T,resetscrollBarStyle:x,get maxScroll(){return q}}},"undefined"!=typeof module&&"object"==typeof exports?module.exports=r:"function"==typeof define&&define.amd?define(function(){return r}):e.kScroll=r}(window,document);
--------------------------------------------------------------------------------
/src/k-scroll.js:
--------------------------------------------------------------------------------
1 | ;(function (window, document) { 'use strict';
2 | var kScroll = {};
3 |
4 | kScroll.bind = function (element, opts) {
5 | var options = {
6 | animationDuration: 200,
7 | animationEasing: [0, 0, 0.58, 1],
8 | speed: 100,
9 | allowMouseDragScroll: true,
10 | checkOnResize: true,
11 | bindKey: true // 绑定按键
12 | };
13 |
14 | configure(opts);
15 |
16 | var wrapper = element;
17 | var scroller = wrapper.querySelector('.k-scroller');
18 | var scrollBar = document.createElement('span');
19 | var minScroll = 0;
20 | var scrollerHeight;
21 | var wrapperHeight;
22 | var scrollBarHeight;
23 | var maxScroll;
24 | var scrollBarHeightPercent;
25 | var scrollBarDragstartScrollTop;
26 | var lastFrameTime;
27 | var frameToken;
28 | var dragEndvScrollTop;
29 | var isDrag;
30 |
31 | var currentScrollTop = 0; // 当前纵向滚动值
32 | var vScrollTop = 0; // 纵向滚动速度
33 |
34 | scrollBar.classList.add('scroll-bar');
35 | wrapper.appendChild(scrollBar);
36 |
37 | var kDrag;
38 |
39 | if (typeof require === 'function')
40 | kDrag = require('kDrag');
41 | else if (window.kDrag)
42 | kDrag = window.kDrag;
43 |
44 | var wrapperDrag = kDrag.bind(wrapper);
45 | var scrollBarDrag = kDrag.bind(scrollBar);
46 |
47 | wrapper.addEventListener('mouseenter', refreshContext);
48 | wrapper.addEventListener('mousedown', refreshContext);
49 | wrapper.addEventListener('touchstart', refreshContext);
50 |
51 | wrapper.addEventListener('mouseenter', wrapperOnMouseenter);
52 | wrapper.addEventListener('mouseleave', wrapperOnMouseleave);
53 |
54 | wrapper.addEventListener('mousedown', _break);
55 | wrapper.addEventListener('touchstart', _break);
56 | window.addEventListener('blur', _break);
57 |
58 | wrapper.addEventListener('mousewheel', onMousewheel);
59 |
60 | wrapper.addEventListener('touchstart', wrapperOnPointerdown);
61 | wrapper.addEventListener('mousedown', wrapperOnPointerdown);
62 |
63 | wrapper.addEventListener('k.dragstart', wrapperOnDragstart);
64 | wrapper.addEventListener('k.drag', wrapperOnDrag);
65 | wrapper.addEventListener('touchend', wrapperOnPointerup);
66 | wrapper.addEventListener('mouseup', wrapperOnPointerup);
67 | wrapper.addEventListener('k.dragend', wrapperOnDragend);
68 |
69 | scrollBar.addEventListener('mouseenter', scrollBarOnMouseenter);
70 | scrollBar.addEventListener('mouseleave', scrollBarOnMouseleave);
71 | scrollBar.addEventListener('touchstart', scrollBarOnPointerdown);
72 | scrollBar.addEventListener('mousedown', scrollBarOnPointerdown);
73 | scrollBar.addEventListener('touchend', scrollBarOnPointerup);
74 | scrollBar.addEventListener('touchcancel', scrollBarOnPointerup);
75 | scrollBar.addEventListener('k.dragstart', scrollBarOnDragstart);
76 | scrollBar.addEventListener('k.drag', scrollBarOnDrag);
77 | scrollBar.addEventListener('k.dragend', scrollBarOnDragend);
78 |
79 | window.addEventListener('resize', resizeCheck);
80 | document.addEventListener('keydown', keyScroll);
81 |
82 | // 强制开启硬件加速
83 | Velocity.hook(scroller, "translateZ", '0.00001px');
84 | Velocity.hook(scrollBar, "translateZ", '0.00001px');
85 | scrollTo(currentScrollTop, false, false);
86 |
87 | return {
88 | unbind: unbind,
89 | configure: configure,
90 | scrollTo: scrollTo,
91 | stopAnimation: stopAnimation,
92 | refreshContext: refreshContext,
93 | resetscrollBarStyle: resetscrollBarStyle,
94 | get maxScroll() {
95 | return maxScroll;
96 | }
97 | };
98 |
99 | function unbind() {
100 | wrapperDrag.unbind();
101 | scrollBarDrag.unbind();
102 |
103 | wrapper.removeEventListener('mouseenter', refreshContext);
104 | wrapper.removeEventListener('mousedown', refreshContext);
105 | wrapper.removeEventListener('touchstart', refreshContext);
106 |
107 | wrapper.removeEventListener('mouseenter', wrapperOnMouseenter);
108 | wrapper.removeEventListener('mouseleave', wrapperOnMouseleave);
109 |
110 | wrapper.removeEventListener('mousedown', _break);
111 | wrapper.removeEventListener('touchstart', _break);
112 | window.removeEventListener('blur', _break);
113 |
114 | wrapper.removeEventListener('mousewheel', onMousewheel);
115 |
116 | wrapper.removeEventListener('touchstart', wrapperOnPointerdown);
117 | wrapper.removeEventListener('mousedown', wrapperOnPointerdown);
118 |
119 | wrapper.removeEventListener('k.dragstart', wrapperOnDragstart);
120 | wrapper.removeEventListener('k.drag', wrapperOnDrag);
121 | wrapper.removeEventListener('touchend', wrapperOnPointerup);
122 | wrapper.removeEventListener('mouseup', wrapperOnPointerup);
123 | wrapper.removeEventListener('k.dragend', wrapperOnDragend);
124 |
125 | scrollBar.removeEventListener('mouseenter', scrollBarOnMouseenter);
126 | scrollBar.removeEventListener('mouseleave', scrollBarOnMouseleave);
127 | scrollBar.removeEventListener('touchstart', scrollBarOnPointerdown);
128 | scrollBar.removeEventListener('mousedown', scrollBarOnPointerdown);
129 | scrollBar.removeEventListener('touchend', scrollBarOnPointerup);
130 | scrollBar.removeEventListener('touchcancel', scrollBarOnPointerup);
131 | scrollBar.removeEventListener('k.dragstart', scrollBarOnDragstart);
132 | scrollBar.removeEventListener('k.drag', scrollBarOnDrag);
133 | scrollBar.removeEventListener('k.dragend', scrollBarOnDragend);
134 |
135 | window.removeEventListener('resize', resizeCheck);
136 | document.removeEventListener('keydown', keyScroll);
137 | }
138 |
139 | function scrollBarOnMouseenter(e) {
140 | var scrollBar = e.currentTarget;
141 | scrollBar.classList.add('hover');
142 | }
143 |
144 | function scrollBarOnMouseleave(e) {
145 | var scrollBar = e.currentTarget;
146 | scrollBar.classList.remove('hover');
147 | }
148 |
149 | function scrollBarOnPointerdown(e) {
150 | e.preventDefault();
151 | var scrollBar = e.currentTarget;
152 | scrollBar.classList.add('active');
153 |
154 | if (e.type === 'mousedown') {
155 | document.addEventListener('mouseup', scrollBarOnPointerup, true);
156 | }
157 | }
158 |
159 | function scrollBarOnPointerup(e) {
160 | scrollBar.classList.remove('active');
161 |
162 | if (e.type === 'mouseup') {
163 | document.removeEventListener('mouseup', scrollBarOnPointerup, true);
164 | }
165 | }
166 |
167 | function scrollBarOnDrag(e) {
168 | var destScrollTop = scrollBarDragstartScrollTop + e.deltaY * (scrollerHeight - wrapperHeight) / (wrapperHeight - scrollBarHeight)
169 | if (destScrollTop > maxScroll)
170 | destScrollTop = maxScroll;
171 | else if (destScrollTop < minScroll)
172 | destScrollTop = minScroll;
173 | scrollTo(destScrollTop, false, false);
174 | }
175 |
176 | function scrollBarOnDragstart(e) {
177 | var scrollBar = e.currentTarget;
178 | refreshContext();
179 | scrollBarDragstartScrollTop = currentScrollTop;
180 | scrollBar.classList.add('dragging');
181 | }
182 |
183 | function scrollBarOnDragend(e) {
184 | var scrollBar = e.currentTarget;
185 | scrollBar.classList.remove('dragging');
186 | }
187 |
188 | function wrapperOnMouseenter(e) {
189 | resetscrollBarStyle();
190 |
191 | var wrapper = e.currentTarget;
192 |
193 | wrapper.classList.add('hover');
194 | }
195 |
196 | function wrapperOnMouseleave(e) {
197 | var wrapper = e.currentTarget;
198 |
199 | wrapper.classList.remove('hover');
200 | }
201 |
202 | function wrapperOnPointerdown(e) {
203 | isDrag = false;
204 |
205 | if (e.type === 'mousedown') {
206 | if (options.allowMouseDragScroll) {
207 | e.preventDefault();
208 | }
209 | }
210 | else {
211 | e.preventDefault();
212 | }
213 | }
214 |
215 | function wrapperOnPointerup(e) {
216 | var wrapper = e.currentTarget;
217 |
218 | if (!isDrag) {
219 | dragEndvScrollTop = 0;
220 | lastFrameTime = null;
221 | wrapper.classList.add('sliding');
222 | slide();
223 | }
224 | }
225 |
226 | function wrapperOnDragstart(e) {
227 | if (e.dragTarget.classList.contains('scroll-bar')) // 如果拖拽的是滚动条就返回
228 | return;
229 | else if (!options.allowMouseDragScroll && e.pointerType === 'mouse' && !e.ctrlKey) {
230 | e.prevent();
231 | return;
232 | }
233 |
234 | var wrapper = e.currentTarget;
235 |
236 | if (e.state > 0) {
237 | wrapper.classList.add('dragging');
238 | isDrag = true;
239 | }
240 | }
241 |
242 | function wrapperOnDrag(e) {
243 | if (e.dragTarget.classList.contains('scroll-bar'))
244 | return;
245 |
246 | if (currentScrollTop > maxScroll) {
247 | if (e.vy <= 0) {
248 | e.stepY /= 1 + Math.abs(currentScrollTop - maxScroll) / 14;
249 | }
250 | } else if (currentScrollTop < minScroll) {
251 | if (e.vy >= 0) {
252 | e.stepY /= 1 + Math.abs(currentScrollTop - minScroll) / 14;
253 | }
254 | }
255 |
256 | vScrollTop = -e.vy;
257 | currentScrollTop -= e.stepY;
258 | scrollTo(currentScrollTop, false, false);
259 | }
260 |
261 | function wrapperOnDragend(e) {
262 | if (e.dragTarget.classList.contains('scroll-bar'))
263 | return;
264 |
265 | var wrapper = e.currentTarget;
266 |
267 | wrapper.classList.remove('dragging');
268 |
269 | dragEndvScrollTop = vScrollTop = -e.vy;
270 |
271 | lastFrameTime = null;
272 | wrapper.classList.add('sliding');
273 | slide();
274 | }
275 |
276 | function onMousewheel(e) {
277 | if (e.ctrlKey)
278 | return;
279 | refreshContext();
280 | e.preventDefault();
281 | var delta = computeMouseWheelDelta(e);
282 | var destScrollTop = currentScrollTop - delta * options.speed;
283 |
284 | if (destScrollTop > maxScroll)
285 | destScrollTop = maxScroll;
286 | else if (destScrollTop < minScroll)
287 | destScrollTop = minScroll;
288 | vScrollTop = 0;
289 | scrollTo(destScrollTop, true, true);
290 | }
291 |
292 | function configure(opts) {
293 | for (var key in opts) {
294 | if (opts[key] !== undefined) {
295 | options[key] = opts[key];
296 | }
297 | }
298 | }
299 |
300 | function keyScroll(e) {
301 | if (!options.bindKey)
302 | return;
303 |
304 | // ←:37 ↑:38 →:39 ↓:40 pgup:33 pgdn:34
305 | switch (e.keyCode) {
306 | case 33:
307 | currentScrollTop -= wrapperHeight - 3;
308 | break;
309 | case 34:
310 | currentScrollTop += wrapperHeight - 3;
311 | break;
312 | case 38:
313 | currentScrollTop -= options.speed;
314 | break;
315 | case 40:
316 | currentScrollTop += options.speed;
317 | break;
318 | default:
319 | return;
320 | }
321 |
322 | refreshContext();
323 |
324 | if (currentScrollTop < minScroll)
325 | currentScrollTop = minScroll;
326 | else if (currentScrollTop > maxScroll)
327 | currentScrollTop = maxScroll;
328 |
329 | scrollTo(currentScrollTop, true, true);
330 | }
331 |
332 | function resizeCheck() {
333 | if (!options.checkOnResize)
334 | return;
335 |
336 | if (wrapper.style.display === 'none')
337 | return;
338 |
339 | refreshContext();
340 | if (currentScrollTop > maxScroll) {
341 | scrollTo(maxScroll);
342 | }
343 | }
344 |
345 | function _break(e, preventTap) {
346 | if (frameToken) {
347 | stopAnimation();
348 | if (e.type !== 'blur' && Math.abs(vScrollTop) > 0.14) {
349 | e.stopPropagation();
350 | e.preventDefault();
351 | }
352 | }
353 | vScrollTop = 0;
354 | wrapper.classList.remove('sliding');
355 |
356 | if (e.ctrlKey && e.type === 'mousedown') {
357 | e.preventDefault();
358 | }
359 | }
360 |
361 | function refreshContext() {
362 | var wrapperStyle = window.getComputedStyle(wrapper);
363 | var scrollerStyle = window.getComputedStyle(scroller);
364 |
365 | wrapperHeight = parseFloat(wrapperStyle.height);
366 | scrollerHeight = parseFloat(scrollerStyle.height);
367 | maxScroll = Math.max(0, scrollerHeight - wrapperHeight);
368 | scrollBarHeightPercent = wrapperHeight / scrollerHeight;
369 | if (scrollBarHeightPercent >= 1) {
370 | scrollBarHeightPercent = 0;
371 | }
372 |
373 | scrollBarHeight = Math.max(wrapperHeight * scrollBarHeightPercent, 56);
374 | }
375 |
376 | function slide(time) {
377 | var timeSpan, destScrollTop, vScrollTopCurrent;
378 |
379 | if (lastFrameTime) {
380 | timeSpan = time - lastFrameTime;
381 |
382 | vScrollTopCurrent = vScrollTop * Math.pow(0.95, timeSpan / (1000 / 60));
383 |
384 | destScrollTop = currentScrollTop + (vScrollTop + vScrollTopCurrent) / 2 * timeSpan;
385 |
386 | scrollTo(destScrollTop, false, false);
387 |
388 | vScrollTop = vScrollTopCurrent;
389 |
390 | if (currentScrollTop > maxScroll) {
391 | if (vScrollTop <= 0) {
392 | vScrollTop = (maxScroll - currentScrollTop) / 200;
393 | if (dragEndvScrollTop < 0 && vScrollTop > dragEndvScrollTop) {
394 | vScrollTop = dragEndvScrollTop;
395 | } else if (vScrollTop > -0.03) {
396 | vScrollTop = -0.03;
397 | }
398 | } else {
399 | vScrollTop -= (currentScrollTop - maxScroll) * 0.0003 * timeSpan;
400 | if (vScrollTop < 0) {
401 | vScrollTop = 0;
402 | }
403 | }
404 | } else if (currentScrollTop < minScroll) {
405 | if (vScrollTop >= 0) {
406 | vScrollTop = (minScroll - currentScrollTop) / 200;
407 | if (dragEndvScrollTop > 0 && vScrollTop < dragEndvScrollTop) {
408 | vScrollTop = dragEndvScrollTop;
409 | } else if (vScrollTop < 0.03) {
410 | vScrollTop = 0.03;
411 | }
412 | } else {
413 | vScrollTop -= (currentScrollTop - minScroll) * 0.0003 * timeSpan;
414 | if (vScrollTop > 0) {
415 | vScrollTop = 0
416 | }
417 | }
418 | }
419 | }
420 |
421 | lastFrameTime = time;
422 |
423 | if (Math.abs(currentScrollTop - maxScroll) < 0.03) {
424 | currentScrollTop = maxScroll;
425 | } else if (Math.abs(currentScrollTop - minScroll) < 0.03) {
426 | currentScrollTop = minScroll;
427 | }
428 |
429 | if (!wrapper.classList.contains('dragging')
430 | && (Math.abs(vScrollTop) > 0.03
431 | || currentScrollTop > maxScroll
432 | || currentScrollTop < minScroll)) {
433 | frameToken = window.requestAnimationFrame(slide);
434 | } else {
435 | vScrollTop = 0;
436 | wrapper.classList.remove('sliding');
437 | window.cancelAnimationFrame(frameToken);
438 | frameToken = null;
439 | }
440 | }
441 |
442 | function resetscrollBarStyle(doAnimation) {
443 | var scrollPercent = currentScrollTop / (scrollerHeight - wrapperHeight);
444 |
445 | if (scrollBarHeightPercent <= 0)
446 | scrollBar.display = 'none';
447 | else
448 | scrollBar.display = 'block';
449 |
450 | Velocity.hook(scrollBar, 'height', scrollBarHeight + 'px');
451 |
452 | Velocity(scrollBar, 'stop');
453 |
454 | var translateY = ((wrapperHeight - scrollBarHeight) * scrollPercent) + 'px';
455 |
456 | if (doAnimation) {
457 | Velocity(scrollBar, {translateY: translateY}, {
458 | duration: options.animationDuration,
459 | easing: options.animationEasing
460 | });
461 | } else {
462 | Velocity.hook(scrollBar, 'translateY', translateY);
463 | }
464 | }
465 |
466 | function scrollTo(destScrollTop, doAnimation, scrollBarDoAnimation, duration, callback) {
467 | currentScrollTop = destScrollTop;
468 |
469 | stopAnimation();
470 |
471 | if (doAnimation) {
472 | Velocity(scroller, {
473 | translateY: (-currentScrollTop) + 'px'
474 | }, {
475 | duration: duration || options.animationDuration,
476 | easing: options.animationEasing,
477 | begin: function () {
478 | wrapper.classList.add('scrolling');
479 | },
480 | complete: function () {
481 | wrapper.classList.remove('scrolling');
482 | if (typeof callback === 'function')
483 | callback.call(this);
484 | }
485 | });
486 | } else {
487 | Velocity.hook(scroller, "translateY", -currentScrollTop + 'px');
488 | if (typeof callback === 'function')
489 | callback.call(this);
490 | }
491 |
492 | resetscrollBarStyle(scrollBarDoAnimation);
493 | }
494 |
495 | function stopAnimation() {
496 | window.cancelAnimationFrame(frameToken);
497 | frameToken = null;
498 | Velocity(scroller, 'stop');
499 | }
500 | };
501 |
502 | function computeMouseWheelDelta(eventArg) {
503 | return (eventArg.wheelDelta) ? eventArg.wheelDelta / 120 : -(eventArg.detail || 0) / 3;
504 | }
505 |
506 | if (typeof module !== 'undefined' && typeof exports === 'object') {
507 | module.exports = kScroll;
508 | } else if (typeof define === 'function' && define.amd) {
509 | define(function() { return kScroll; });
510 | } else {
511 | window.kScroll = kScroll;
512 | }
513 | })(window, document);
514 |
--------------------------------------------------------------------------------