Winceptor created this userscript, which uses JavaScript to enable smooth page scrolling. I just made it better.
当前为
// ==UserScript==
// @name Smooth Scroll Function
// @description Winceptor created this userscript, which uses JavaScript to enable smooth page scrolling. I just made it better.
// @author DXRK1E
// @icon https://i.imgur.com/IAwk6NN.png
// @include *
// @exclude https://www.youtube.com/*
// @exclude https://mail.google.com/*
// @version 1.3
// @namespace sttb-dxrk1e
// @license MIT
// ==/UserScript==
(function () {
var Smoothscroll = {};
// settings
Smoothscroll.Smoothness = 0.5;
Smoothscroll.Acceleration = 0.5;
// debug
Smoothscroll.Debug = 0; // 0-none, 1-some, etc.
// 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;
}
}
function AnimateScroll(target, refreshrate) {
var scrollsubpixels = ScrollSubpixels(target);
var scrollpixels = ScrollPixels(target);
var scrolldirection = scrollpixels > 0 ? 1 : scrollpixels < 0 ? -1 : 0;
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;
target.style.scrollBehavior = "auto"; // fix for pages with changed scroll-behavior
target.scrollTop = target.scrollTop + scrolldelta;
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(function () {
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);
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);
}
}
};
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) {
if (element === window || element === document) {
return false;
}
if (element === document.body) {
return window.getComputedStyle(document.body)['overflow-y'] !== "hidden";
}
if (element === document.documentElement) {
return window.innerWidth > document.documentElement.clientWidth;
} else {
var style = window.getComputedStyle(element);
return style['overflow-y'] !== "hidden" && style['overflow-y'] !== "visible";
}
}
function Scrollable(element, dir) {
if (element === document.body) {
// return false;
}
var scrollablecheck = CanScroll(element, dir);
if (!scrollablecheck) {
return false;
}
var scrollbarcheck = HasScrollbar(element);
if (!scrollbarcheck) {
return false;
}
return true;
}
function GetPath(e) {
if (e.path) {
return e.path;
}
if (e.composedPath) {
return e.composedPath();
}
return null;
}
function GetTarget(e) {
var direction = e.deltaY;
var nodes = GetPath(e);
if (!nodes) {
return null;
}
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (Scrollable(node, direction)) {
return node;
}
}
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;
}
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 (e.deltaMode && e.deltaMode === 1) {
var line = GetStyleProperty(target, 'line-height');
if (line && line > 0) {
delta = e.deltaY * line;
}
}
if (e.deltaMode && e.deltaMode === 2) {
var page = target.clientHeight;
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;
Smoothscroll.Start(target, totalscroll);
e.preventDefault();
}
}
function WheelEvent(e) {
var target = GetTarget(e);
if (target) {
StartScroll(e, target);
}
}
function ClickEvent(e) {
StopScroll(e);
}
function Init() {
if (window.top !== window.self) {
return null;
}
if (window.Smoothscroll && window.Smoothscroll.Loaded) {
return null;
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame;
}
document.documentElement.addEventListener("wheel", function (e) {
WheelEvent(e);
}, { passive: false });
document.documentElement.addEventListener("mousedown", function (e) {
ClickEvent(e);
});
window.Smoothscroll = Smoothscroll;
window.Smoothscroll.Loaded = true;
console.log("Smoothscroll: loaded");
}
Init();
})();
// Ignore this; it's just a credits screen that appears on the devtools console only.
console.log(
'%cDarkPulse\n%cUSERSCRIPT: %cSmooth Scroll Function\n%cDeveloped by %cDXRK1E',
'color: #8C52FF; font-size: 36px; font-weight: bold; margin: 20px 0;',
'color: white; font-size: 20px; font-weight: bold; margin: 20px 0 0 20px;',
'color: #B0BFFB; font-size: 20px; font-weight: bold; margin: 20px 0;',
'color: white; font-size: 16px; margin: 20px 0 0 20px;',
'color: #615EFC; font-size: 16px; font-weight: bold; margin: 20px 0;'
);