Greasy Fork 还支持 简体中文。

Smoothscroll

Smooth scrolling on pages using javascript

目前為 2021-05-16 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Smoothscroll
  3. // @author Creec Winceptor
  4. // @description Smooth scrolling on pages using javascript
  5. // @namespace https://greasyfork.org/users/3167
  6. // @include *
  7. // @version 10.0
  8. // ==/UserScript==
  9.  
  10. var Smoothscroll = {};
  11.  
  12.  
  13. //settings
  14. Smoothscroll.Smoothness = 0.5;
  15. Smoothscroll.Acceleration = 0.5;
  16.  
  17.  
  18. //debug
  19. Smoothscroll.Debug = false;
  20. //autodetected
  21. Smoothscroll.Refreshrate = 60;
  22.  
  23. //scrolling and animation
  24. function ScrollSubpixels(element, newvalue)
  25. {
  26. if (newvalue!=undefined)
  27. {
  28. element.scrollsubpixels = newvalue;
  29. return newvalue;
  30. }
  31. else
  32. {
  33. var olddelta = element.scrollsubpixels;
  34. if (olddelta!=undefined)
  35. {
  36. return olddelta;
  37. }
  38. return 0;
  39. }
  40. }
  41. function ScrollPixels(element, newvalue)
  42. {
  43. if (newvalue!=undefined)
  44. {
  45. element.scrollpixels = newvalue;
  46. ScrollSubpixels(element, 0);
  47. return newvalue;
  48. }
  49. else
  50. {
  51. var olddelta = element.scrollpixels;
  52. if (olddelta!=undefined)
  53. {
  54. return olddelta;
  55. }
  56. return 0;
  57. }
  58. }
  59.  
  60. var last = 0;
  61. function AnimateScroll(target, now) {
  62. var scrollsubpixels = ScrollSubpixels(target);
  63. var scrollpixels = ScrollPixels(target);
  64.  
  65. if (Smoothscroll.Debug) {
  66. console.log("scrollpixels: " + scrollpixels);
  67. }
  68. if (Smoothscroll.Debug) {
  69. console.log("target: ", target);
  70. if (target == document.documentElement) {
  71. console.log("document.documentElement");
  72. }
  73. }
  74.  
  75. var scrolldirection = 0;
  76. if (scrollpixels>0) {
  77. scrolldirection = 1;
  78. }
  79. if (scrollpixels<0) {
  80. scrolldirection = -1;
  81. }
  82.  
  83. var scrollratio = 1-Math.pow( Smoothscroll.Refreshrate, -1/(Smoothscroll.Refreshrate*Smoothscroll.Smoothness));
  84. var scrollrate = scrollpixels*scrollratio;
  85. if (Math.abs(scrollpixels)>1) {
  86. var fullscrolls = Math.floor(Math.abs(scrollrate))*scrolldirection;
  87. var scrollsubpixelsadded = scrollrate - fullscrolls;
  88.  
  89. var additionalscrolls = Math.floor(Math.abs(scrollsubpixels + scrollsubpixelsadded))*scrolldirection;
  90. var scrollsubpixelsleft = scrollsubpixels + scrollsubpixelsadded - additionalscrolls;
  91.  
  92. ScrollPixels(target, scrollpixels-fullscrolls-additionalscrolls);
  93. ScrollSubpixels(target, scrollsubpixelsleft);
  94. var scrolldelta = fullscrolls + additionalscrolls;
  95. if (Smoothscroll.Debug) {
  96. console.log("scrolldelta: " + scrolldelta);
  97. }
  98.  
  99. if (target.scrollBy != null) {
  100. target.scrollBy({
  101. top: scrolldelta,
  102. left: 0,
  103. behavior: 'auto'
  104. });
  105. } else {
  106. target.style.scrollBehavior="auto"; // fix for pages with changed scroll-behavior
  107. target.scrollTop = target.scrollTop + scrolldelta;
  108. }
  109.  
  110.  
  111. if (Smoothscroll.Debug) {
  112. console.log("target.scrollTop: " + target.scrollTop);
  113. }
  114.  
  115. target.scrollanimated = true;
  116. window.requestAnimationFrame(function() {
  117. AnimateScroll(target);
  118. });
  119. } else
  120. {
  121. window.requestAnimationFrame(function() {
  122. ScrollPixels(target, 0);
  123. });
  124. target.scrollanimated = false;
  125. }
  126. }
  127.  
  128. Smoothscroll.Stop = function(target) {
  129. if (target) {
  130. ScrollPixels(target, 0);
  131. }
  132. }
  133. Smoothscroll.Start = function(target, scrollamount) {
  134. if (target) {
  135. var scrolltotal = ScrollPixels(target, scrollamount);
  136. if (!target.scrollanimated) {
  137. AnimateScroll(target);
  138. }
  139.  
  140. //var scrollpixels = ScrollPixels(target);
  141.  
  142. }
  143. }
  144.  
  145. if (typeof module !== 'undefined') {
  146. module.exports = Smoothscroll;
  147. }
  148.  
  149.  
  150. function CanScroll(element, dir) {
  151.  
  152. if (dir<0)
  153. {
  154. return element.scrollTop>0;
  155. }
  156. if (dir>0)
  157. {
  158. if (element==document.body) {
  159. if (element.scrollTop==0) {
  160. element.scrollTop = 3;
  161. if (element.scrollTop==0) {
  162. return false;
  163. }
  164. element.scrollTop = 0;
  165. }
  166. return Math.round(element.clientHeight+element.scrollTop)<(element.offsetHeight);
  167. }
  168. return Math.round(element.clientHeight+element.scrollTop)<(element.scrollHeight);
  169. }
  170. }
  171. function HasScrollbar(element)
  172. {
  173. //TODO: problem with webkit, body not scrollable?
  174. if (element==window || element==document) {
  175. return false;
  176. }
  177. if (element==document.body) {
  178. return window.getComputedStyle(document.body)['overflow-y']!="hidden";
  179. }
  180. //THANK YOU TO: https://tylercipriani.com/blog/2014/07/12/crossbrowser-javascript-scrollbar-detection/
  181. if (element==document.documentElement) {
  182. return window.innerWidth > document.documentElement.clientWidth;
  183. } else {
  184. //return (element.clientWidth-element.clientWidth)>0;
  185. var style = window.getComputedStyle(element);
  186. return style['overflow-y']!="hidden" && style['overflow-y']!="visible";
  187. }
  188.  
  189. }
  190.  
  191. function Scrollable(element, dir)
  192. {
  193. //TODO: problem with webkit, body not scrollable?
  194. if (element==document.body) {
  195. //return false;
  196. }
  197. var scrollablecheck = CanScroll(element, dir);
  198. if (!scrollablecheck) {
  199. if (Smoothscroll.Debug) {
  200. console.log("scrollablecheck: " + scrollablecheck);
  201. }
  202. return false;
  203. }
  204. var scrollbarcheck = HasScrollbar(element);
  205. if (!scrollbarcheck) {
  206. if (Smoothscroll.Debug) {
  207. console.log("scrollbarcheck: " + scrollbarcheck);
  208. }
  209. return false;
  210. }
  211.  
  212. if (Smoothscroll.Debug) {
  213. console.log("scrollablecheck: " + scrollablecheck);
  214. console.log("scrollbarcheck: " + scrollbarcheck);
  215. }
  216. return true;
  217. }
  218. function GetPath(e) {
  219. if (e.path) {
  220. return e.path;
  221. }
  222. if (e.composedPath) {
  223. return e.composedPath();
  224. }
  225. if (Smoothscroll.Debug) {
  226. console.log("Smoothscroll: e.path is undefined");
  227. }
  228. return null;
  229. }
  230.  
  231. function GetTarget(e) {
  232. var direction = e.deltaY;
  233. var nodes = GetPath(e);
  234. if (!nodes) {
  235. return null;
  236. }
  237. if (Smoothscroll.Debug) {
  238. console.log("nodes: ");
  239. console.log(nodes);
  240. console.log("target: ");
  241. }
  242. for (var i=0; i<(nodes.length); i++) {
  243. var node = nodes[i];
  244. if (Smoothscroll.Debug) {
  245. console.log(node);
  246. }
  247. if (Scrollable(node, direction))
  248. {
  249. if (Smoothscroll.Debug) {
  250. console.log("true");
  251. }
  252. return node;
  253. }
  254. }
  255. if (Smoothscroll.Debug) {
  256. console.log("false");
  257.  
  258. }
  259.  
  260. return null;
  261. }
  262.  
  263. function GetStyleProperty(el, styleprop){
  264. if(window.getComputedStyle){
  265. var heightprop = document.defaultView.getComputedStyle(el, null).getPropertyValue(styleprop);
  266. if (heightprop) {
  267. return parseInt(heightprop);
  268. }
  269. }
  270. else if(el.currentStyle){
  271. var heightprop = el.currentStyle[styleprop.encamel()];
  272. if (heightprop) {
  273. return parseInt(heightprop);
  274. }
  275. }
  276. return null;
  277. }
  278.  
  279. //mouse event scroll handlers
  280. function StopScroll(e) {
  281. var nodes = GetPath(e);
  282. if (!nodes) {
  283. return null;
  284. }
  285.  
  286. for (var i=0; i<(nodes.length); i++) {
  287. var node = nodes[i];
  288. Smoothscroll.Stop(node);
  289. }
  290. }
  291. function StartScroll(e, target) {
  292.  
  293. if (e.defaultPrevented)
  294. {
  295. return true;
  296. }
  297. else
  298. {
  299. var delta = e.deltaY;
  300.  
  301. if (e.deltaMode && e.deltaMode==1) {
  302. var line = GetStyleProperty(target, 'line-height');
  303. if (line && line>0) {
  304. delta = e.deltaY * line;
  305. }
  306. }
  307.  
  308. if (e.deltaMode && e.deltaMode==2) {
  309. var page = target.clientHeight;
  310. if (page && page>0) {
  311. delta = e.deltaY * page;
  312. }
  313. }
  314.  
  315. var scrollpixels = ScrollPixels(target);
  316.  
  317. var accelerationratio = Math.sqrt(Math.abs(scrollpixels/delta*Smoothscroll.Acceleration));
  318.  
  319. var acceleration = Math.round(delta*accelerationratio);
  320.  
  321. Smoothscroll.Start(target, scrollpixels + delta + acceleration);
  322.  
  323. e.preventDefault();
  324. }
  325. }
  326.  
  327. //mouse event call handlers
  328. function WheelEvent(e) {
  329. var target = GetTarget(e);
  330.  
  331. if (target) {
  332. StartScroll(e, target);
  333. }
  334. }
  335. function ClickEvent(e) {
  336. StopScroll(e);
  337. }
  338.  
  339. var now0 = null;
  340. function Fps(now) {
  341. if (now0 != null) {
  342. Smoothscroll.Refreshrate = 1000 / (now - now0);
  343. }
  344. now0 = now;
  345.  
  346. window.requestAnimationFrame(Fps);
  347. };
  348.  
  349. //init function
  350. function Init()
  351. {
  352.  
  353. if (window.top != window.self) {
  354. //console.log("Smoothscroll: ignoring iframe");
  355. return null;
  356. }
  357. if (window.Smoothscroll && window.Smoothscroll.Loaded) {
  358. //console.log("Smoothscroll: already loaded");
  359. return null;
  360. }
  361.  
  362. if (!window.requestAnimationFrame) {
  363. window.requestAnimationFrame =
  364. window.mozRequestAnimationFrame ||
  365. window.webkitRequestAnimationFrame;
  366. }
  367.  
  368. document.documentElement.addEventListener("wheel", function(e){
  369. WheelEvent(e);
  370. if (Smoothscroll.Debug) {
  371. console.log(e);
  372. }
  373. },{ passive: false });
  374.  
  375. document.documentElement.addEventListener("mousedown", function(e){
  376. ClickEvent(e);
  377. if (Smoothscroll.Debug) {
  378. console.log(e);
  379. }
  380. });
  381. window.Smoothscroll = Smoothscroll;
  382. window.Smoothscroll.Loaded = true;
  383. window.requestAnimationFrame(Fps);
  384. console.log("Smoothscroll: loaded");
  385. }
  386. Init();