您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Smooth scrolling on pages using javascript
- // ==UserScript==
- // @name Smoothscroll
- // @author Creec Winceptor
- // @description Smooth scrolling on pages using javascript
- // @namespace https://greasyfork.org/users/3167
- // @include *
- // @version 12
- // ==/UserScript==
- var Smoothscroll = {};
- //settings
- Smoothscroll.Smoothness = 0.5;
- Smoothscroll.Acceleration = 0.5;
- //debug
- Smoothscroll.Debug = 0; //0-none, 1-some, etc.
- /*
- //initial fps, no need to change
- Smoothscroll.BaseRefreshrate = 60;
- Smoothscroll.MaxRefreshrate = Smoothscroll.BaseRefreshrate*3;
- Smoothscroll.MinRefreshrate = Smoothscroll.BaseRefreshrate/3;
- */
- //automatically calculated
- Smoothscroll.Refreshrate = 60;
- Smoothscroll.MaxRefreshrate = 300;
- Smoothscroll.MinRefreshrate = 1;
- //scrolling and animation
- function ScrollSubpixels(element, newvalue)
- {
- if (newvalue!=undefined)
- {
- element.scrollsubpixels = newvalue;
- return newvalue;
- }
- else
- {
- var olddelta = element.scrollsubpixels;
- if (olddelta!=undefined)
- {
- return olddelta;
- }
- return 0;
- }
- }
- function ScrollPixels(element, newvalue)
- {
- if (newvalue!=undefined)
- {
- element.scrollpixels = newvalue;
- ScrollSubpixels(element, 0);
- return newvalue;
- }
- else
- {
- var olddelta = element.scrollpixels;
- if (olddelta!=undefined)
- {
- return olddelta;
- }
- return 0;
- }
- }
- var last = 0;
- function AnimateScroll(target, refreshrate) {
- var scrollsubpixels = ScrollSubpixels(target);
- var scrollpixels = ScrollPixels(target);
- if (Smoothscroll.Debug>3) {
- console.log("scrollpixels: " + scrollpixels);
- }
- if (Smoothscroll.Debug>3) {
- console.log("target: ", target);
- if (target == document.documentElement) {
- console.log("document.documentElement");
- }
- }
- var scrolldirection = 0;
- if (scrollpixels>0) {
- scrolldirection = 1;
- }
- if (scrollpixels<0) {
- scrolldirection = -1;
- }
- var scrollratio = 1-Math.pow( refreshrate, -1/(refreshrate*Smoothscroll.Smoothness));
- var scrollrate = scrollpixels*scrollratio;
- if (Math.abs(scrollpixels)>2) {
- var fullscrolls = Math.floor(Math.abs(scrollrate))*scrolldirection;
- var scrollsubpixelsadded = scrollrate - fullscrolls;
- var additionalscrolls = Math.floor(Math.abs(scrollsubpixels + scrollsubpixelsadded))*scrolldirection;
- var scrollsubpixelsleft = scrollsubpixels + scrollsubpixelsadded - additionalscrolls;
- ScrollPixels(target, scrollpixels-fullscrolls-additionalscrolls);
- ScrollSubpixels(target, scrollsubpixelsleft);
- var scrolldelta = fullscrolls + additionalscrolls;
- if (Smoothscroll.Debug>1) {
- console.log("scrolldelta: " + scrolldelta);
- }
- /*
- if (target.scrollBy != null) {
- target.scrollBy({
- top: scrolldelta,
- left: 0,
- behavior: 'auto'
- });
- if (Smoothscroll.Debug>1) {
- console.log("target.scrollBy: " + scrolldelta);
- }
- } else {
- */
- target.style.scrollBehavior="auto"; // fix for pages with changed scroll-behavior
- target.scrollTop = target.scrollTop + scrolldelta;
- if (Smoothscroll.Debug>1) {
- console.log("target.scrollTop: " + target.scrollTop);
- }
- target.scrollanimated = true;
- RequestAnimationUpdate(function(newrefreshrate) {
- AnimateScroll(target, newrefreshrate);
- });
- } else
- {
- RequestAnimationUpdate(function(newrefreshrate) {
- ScrollPixels(target, 0);
- });
- target.scrollanimated = false;
- }
- }
- function RequestAnimationUpdate(cb) {
- var before = performance.now();
- window.requestAnimationFrame(() => {
- var after = performance.now();
- var frametime = after - before;
- var calculatedFps = 1000 / Math.max(frametime, 1);
- var refreshrate = Math.min(Math.max(calculatedFps, Smoothscroll.MinRefreshrate), Smoothscroll.MaxRefreshrate);
- //Smoothscroll.Refreshrate = refreshrate;
- cb(refreshrate);
- });
- }
- Smoothscroll.Stop = function(target) {
- if (target) {
- ScrollPixels(target, 0);
- }
- }
- Smoothscroll.Start = function(target, scrollamount) {
- if (target) {
- var scrolltotal = ScrollPixels(target, scrollamount);
- if (!target.scrollanimated) {
- AnimateScroll(target, Smoothscroll.Refreshrate);
- }
- //var scrollpixels = ScrollPixels(target);
- }
- }
- if (typeof module !== 'undefined') {
- module.exports = Smoothscroll;
- }
- function CanScroll(element, dir) {
- if (dir<0)
- {
- return element.scrollTop>0;
- }
- if (dir>0)
- {
- if (element==document.body) {
- if (element.scrollTop==0) {
- element.scrollTop = 3;
- if (element.scrollTop==0) {
- return false;
- }
- element.scrollTop = 0;
- }
- return Math.round(element.clientHeight+element.scrollTop)<(element.offsetHeight);
- }
- return Math.round(element.clientHeight+element.scrollTop)<(element.scrollHeight);
- }
- }
- function HasScrollbar(element)
- {
- //TODO: problem with webkit, body not scrollable?
- if (element==window || element==document) {
- return false;
- }
- if (element==document.body) {
- return window.getComputedStyle(document.body)['overflow-y']!="hidden";
- }
- //THANK YOU TO: https://tylercipriani.com/blog/2014/07/12/crossbrowser-javascript-scrollbar-detection/
- if (element==document.documentElement) {
- return window.innerWidth > document.documentElement.clientWidth;
- } else {
- //return (element.clientWidth-element.clientWidth)>0;
- var style = window.getComputedStyle(element);
- return style['overflow-y']!="hidden" && style['overflow-y']!="visible";
- }
- }
- function Scrollable(element, dir)
- {
- //TODO: problem with webkit, body not scrollable?
- if (element==document.body) {
- //return false;
- }
- var scrollablecheck = CanScroll(element, dir);
- if (!scrollablecheck) {
- if (Smoothscroll.Debug>1) {
- console.log("scrollablecheck: " + scrollablecheck);
- }
- return false;
- }
- var scrollbarcheck = HasScrollbar(element);
- if (!scrollbarcheck) {
- if (Smoothscroll.Debug>1) {
- console.log("scrollbarcheck: " + scrollbarcheck);
- }
- return false;
- }
- if (Smoothscroll.Debug>1) {
- console.log("scrollablecheck: " + scrollablecheck);
- console.log("scrollbarcheck: " + scrollbarcheck);
- }
- return true;
- }
- function GetPath(e) {
- if (e.path) {
- return e.path;
- }
- if (e.composedPath) {
- return e.composedPath();
- }
- if (Smoothscroll.Debug>1) {
- console.log("Smoothscroll: e.path is undefined");
- }
- return null;
- }
- function GetTarget(e) {
- var direction = e.deltaY;
- var nodes = GetPath(e);
- if (!nodes) {
- return null;
- }
- if (Smoothscroll.Debug>2) {
- console.log("nodes: ");
- console.log(nodes);
- console.log("target: ");
- }
- for (var i=0; i<(nodes.length); i++) {
- var node = nodes[i];
- if (Smoothscroll.Debug>2) {
- console.log(node);
- }
- if (Scrollable(node, direction))
- {
- if (Smoothscroll.Debug>2) {
- console.log("true");
- }
- return node;
- }
- }
- if (Smoothscroll.Debug>1) {
- console.log("false");
- }
- return null;
- }
- function GetStyleProperty(el, styleprop){
- if(window.getComputedStyle){
- var heightprop = document.defaultView.getComputedStyle(el, null).getPropertyValue(styleprop);
- if (heightprop) {
- return parseInt(heightprop);
- }
- }
- else if(el.currentStyle){
- var heightprop = el.currentStyle[styleprop.encamel()];
- if (heightprop) {
- return parseInt(heightprop);
- }
- }
- return null;
- }
- //mouse event scroll handlers
- function StopScroll(e) {
- var nodes = GetPath(e);
- if (!nodes) {
- return null;
- }
- for (var i=0; i<(nodes.length); i++) {
- var node = nodes[i];
- Smoothscroll.Stop(node);
- }
- }
- function StartScroll(e, target) {
- if (e.defaultPrevented)
- {
- return true;
- }
- else
- {
- var delta = e.deltaY;
- if (Smoothscroll.Debug) {
- console.log("e: ", e);
- }
- if (e.deltaMode && e.deltaMode==1) {
- var line = GetStyleProperty(target, 'line-height');
- if (Smoothscroll.Debug) {
- console.log("line: " + line);
- }
- if (line && line>0) {
- delta = e.deltaY * line;
- }
- }
- if (e.deltaMode && e.deltaMode==2) {
- var page = target.clientHeight;
- if (Smoothscroll.Debug) {
- console.log("page: " + page);
- }
- if (page && page>0) {
- delta = e.deltaY * page;
- }
- }
- var scrollpixels = ScrollPixels(target);
- var accelerationratio = Math.sqrt(Math.abs(scrollpixels/delta*Smoothscroll.Acceleration));
- var acceleration = Math.round(delta*accelerationratio);
- var totalscroll = scrollpixels + delta + acceleration;
- if (Smoothscroll.Debug) {
- console.log("scrollpixels: " + scrollpixels);
- console.log("delta: " + delta);
- console.log("acceleration: " + acceleration);
- console.log("totalscroll: " + totalscroll);
- }
- Smoothscroll.Start(target, totalscroll);
- e.preventDefault();
- }
- }
- //mouse event call handlers
- function WheelEvent(e) {
- var target = GetTarget(e);
- if (target) {
- StartScroll(e, target);
- }
- }
- function ClickEvent(e) {
- StopScroll(e);
- }
- /*
- function GetFrametime(cb) {
- var before = performance.now();
- window.requestAnimationFrame(() => {
- var after = performance.now();
- var diff = after - before;
- if (cb) {
- cb(diff);
- }
- });
- }
- function UpdateRefreshrateInternal(cb) {
- GetFrametime((frametime) => {
- var calculatedFps = 1000 / Math.max(frametime, 1);
- Smoothscroll.Refreshrate = Math.min(Math.max(calculatedFps, Smoothscroll.MinRefreshrate), Smoothscroll.MaxRefreshrate);
- if (Smoothscroll.Debug > 3) {
- console.log("Smoothscroll.Refreshrate: " + Smoothscroll.Refreshrate);
- }
- if (cb) {
- cb();
- }
- });
- }
- var updateRefreshrateLoopTimer = null;
- function UpdateRefreshrate() {
- if (updateRefreshrateLoopTimer) {
- clearTimeout(updateRefreshrateLoopTimer);
- }
- UpdateRefreshrateInternal(()=>{
- updateRefreshrateLoopTimer = setTimeout(()=>{
- UpdateRefreshrate();
- },1000/Smoothscroll.BaseRefreshrate);
- });
- };
- */
- //init function
- function Init()
- {
- if (window.top != window.self) {
- //console.log("Smoothscroll: ignoring iframe");
- return null;
- }
- if (window.Smoothscroll && window.Smoothscroll.Loaded) {
- //console.log("Smoothscroll: already loaded");
- return null;
- }
- //Smoothscroll.Refreshrate = Smoothscroll.BaseRefreshrate;
- if (!window.requestAnimationFrame) {
- window.requestAnimationFrame =
- window.mozRequestAnimationFrame ||
- window.webkitRequestAnimationFrame;
- }
- document.documentElement.addEventListener("wheel", function(e){
- WheelEvent(e);
- if (Smoothscroll.Debug>0) {
- console.log(e);
- }
- },{ passive: false });
- document.documentElement.addEventListener("mousedown", function(e){
- ClickEvent(e);
- if (Smoothscroll.Debug>0) {
- console.log(e);
- }
- });
- window.Smoothscroll = Smoothscroll;
- window.Smoothscroll.Loaded = true;
- //window.requestAnimationFrame(Fps);
- //UpdateRefreshrate();
- //UpdateRefreshrate();
- console.log("Smoothscroll: loaded");
- }
- Init();