// ==UserScript==
// @name 📕无动画全屏翻页丨墨水屏一键翻页丨保留比例翻页丨自定义比例
// @version 2.2
// @description 👍忽略滑动动画,快速切换页面,可以通过键盘或浮动窗口进行操作,并调整黑色模式、悬浮窗大小和滑动保留页面比例。
// @author Jingyu0123
// @match *://*/*
// @license GPL
// @namespace https://gf.qytechs.cn/users/1292046
// ==/UserScript==
(function () {
'use strict';
// 默认配置变量
const autoDetectModeOptions = ['关闭', '同色', '反色'];
var usePgUpPgDn = GM_getValue('usePgUpPgDn', true);
var reservedHeightPercentage = GM_getValue('reservedHeightPercentage', 0);
var isBlackMode = GM_getValue('isBlackMode', false);
var floatWindowSize = GM_getValue('floatWindowSize', 80);
var autoDetectMode = GM_getValue('autoDetectMode', '关闭');
var isVerticalLayout = GM_getValue('isVerticalLayout', true);
var windowOpacity = GM_getValue('windowOpacity', 0.8);
var textOpacity = GM_getValue('textOpacity', 1.0);
var floatWindowVisible = GM_getValue('floatWindowVisible', true);
var upKey = GM_getValue('upKey', 'PageUp');
var downKey = GM_getValue('downKey', 'PageDown');
var enableHotkeys = GM_getValue('enableHotkeys', true);
// 自动检测黑色模式
function detectDarkMode() {
const bgColor = window.getComputedStyle(document.body).backgroundColor;
const colorValues = bgColor.match(/\d+/g);
if (colorValues) {
const r = parseInt(colorValues[0]);
const g = parseInt(colorValues[1]);
const b = parseInt(colorValues[2]);
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
return brightness < 128;
}
return false;
}
if (autoDetectMode === '同色') {
isBlackMode = detectDarkMode();
} else if (autoDetectMode === '反色') {
isBlackMode = !detectDarkMode();
}
// 创建悬浮窗
function createFloatingWindow() {
// 检查是否已经存在浮窗
if (document.getElementById('floatingWindow')) {
return; // 如果已经存在浮窗,则不创建新的浮窗
}
if (!floatWindowVisible) return;
const floatWindow = document.createElement('div');
floatWindow.id = 'floatingWindow'; // 为浮窗设置一个唯一的ID
const initialLeft = GM_getValue('floatWindowLeft', 'calc(100% - 90px)');
const initialTop = GM_getValue('floatWindowTop', 'calc(100% - 270px)');
floatWindow.style = `
position: fixed;
left: ${initialLeft};
top: ${initialTop};
width: ${isVerticalLayout ? floatWindowSize + 'px' : (floatWindowSize * 3) + 'px'};
height: ${isVerticalLayout ? (floatWindowSize * 3) + 'px' : floatWindowSize + 'px'};
background-color: ${isBlackMode ? 'black' : 'white'};
color: ${isBlackMode ? 'white' : 'black'};
border: 1px solid #ccc;
z-index: 10000;
display: flex;
flex-direction: ${isVerticalLayout ? 'column' : 'row'};
align-items: center;
justify-content: space-around;
cursor: move;
padding: 5px;
border-radius: 5px;
opacity: ${windowOpacity};
`;
floatWindow.draggable = true;
const btnSettings = document.createElement('button');
btnSettings.innerHTML = '=';
btnSettings.style = buttonStyle();
btnSettings.onclick = showSettings;
const btnDown = document.createElement('button');
btnDown.innerHTML = '↓';
btnDown.style = buttonStyle();
btnDown.onclick = () => scrollPage(1);
const btnUp = document.createElement('button');
btnUp.innerHTML = '↑';
btnUp.style = buttonStyle();
btnUp.onclick = () => scrollPage(-1);
floatWindow.appendChild(btnSettings);
floatWindow.appendChild(btnUp);
floatWindow.appendChild(btnDown);
document.body.appendChild(floatWindow);
// 悬浮窗拖拽功能
floatWindow.addEventListener('dragstart', (event) => {
const style = window.getComputedStyle(event.target, null);
event.dataTransfer.setData('text/plain',
(parseInt(style.getPropertyValue('left'), 10) - event.clientX) + ',' +
(parseInt(style.getPropertyValue('top'), 10) - event.clientY));
}, false);
document.body.addEventListener('dragover', (event) => {
event.preventDefault();
return false;
}, false);
document.body.addEventListener('drop', (event) => {
const offset = event.dataTransfer.getData('text/plain').split(',');
const floatWindow = document.querySelector('div[draggable="true"]');
const left = (event.clientX + parseInt(offset[0], 10)) + 'px';
const top = (event.clientY + parseInt(offset[1], 10)) + 'px';
floatWindow.style.left = left;
floatWindow.style.top = top;
GM_setValue('floatWindowLeft', left);
GM_setValue('floatWindowTop', top);
event.preventDefault();
return false;
}, false);
}
// 滚动页面函数
function scrollPage(direction) {
const screenHeight = window.innerHeight;
const reservedHeight = screenHeight * reservedHeightPercentage / 100;
window.scrollBy(0, direction * (screenHeight - reservedHeight));
}
// 键盘事件监听
window.addEventListener('keydown', function (event) {
if (!enableHotkeys) return; // 检查是否启用热键
const screenHeight = window.innerHeight;
const reservedHeight = screenHeight * reservedHeightPercentage / 100;
if ((event.key === upKey || event.key === downKey)) {
const direction = event.key === downKey ? 1 : -1;
window.scrollBy(0, direction * (screenHeight - reservedHeight));
event.preventDefault();
}
});
// 显示设置窗口
function showSettings() {
const settingsWindow = document.createElement('div');
settingsWindow.style = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
background-color: ${isBlackMode ? 'black' : 'white'};
color: ${isBlackMode ? 'white' : 'black'};
border: 1px solid #ccc;
z-index: 10001;
padding: 20px;
border-radius: 5px;
`;
const settingsContainer = document.createElement('div');
settingsContainer.style = `
display: flex;
flex-direction: column;
align-items: flex-start;
color: ${isBlackMode ? 'white' : 'black'};
`;
// 更新颜色
const updateColors = () => {
settingsWindow.style.backgroundColor = isBlackMode ? 'black' : 'white';
settingsWindow.style.color = isBlackMode ? 'white' : 'black';
settingsContainer.style.color = isBlackMode ? 'white' : 'black';
saveButton.style.backgroundColor = isBlackMode ? 'black' : 'white';
saveButton.style.color = isBlackMode ? 'white' : 'black';
donateButton.style.backgroundColor = isBlackMode ? 'black' : 'white';
donateButton.style.color = isBlackMode ? 'white' : 'black';
};
// 样式设置
const createSetting = (labelText, value, onClick) => {
const container = document.createElement('div');
container.style = `
display: flex;
justify-content: space-between;
width: 100%;
margin-bottom: 10px;
cursor: pointer;
`;
container.onclick = onClick;
const label = document.createElement('span');
label.innerText = labelText;
container.appendChild(label);
const indicator = document.createElement('span');
indicator.innerText = value ? '✔️' : '✖️';
container.appendChild(indicator);
return container;
};
const modeSetting = createSetting('🌑黑色模式', isBlackMode, () => {
isBlackMode = !isBlackMode;
modeSetting.lastChild.innerText = isBlackMode ? '✔️' : '✖️';
GM_setValue('isBlackMode', isBlackMode);
updateColors();
});
const createAutoDetectSetting = (labelText, currentOption, optionValue) => {
const container = document.createElement('div');
container.style = `
display: flex;
justify-content: space-between;
align-items: center;
flex: 1;
margin-bottom: 10px;
cursor: pointer;
padding-right: 10px;
`;
container.onclick = () => {
autoDetectMode = optionValue;
GM_setValue('autoDetectMode', autoDetectMode);
updateAutoDetectSettings();
};
const label = document.createElement('span');
label.innerText = labelText;
container.appendChild(label);
const indicator = document.createElement('span');
indicator.innerText = (currentOption === optionValue) ? '✔️' : '✖️';
container.appendChild(indicator);
return container;
};
const updateAutoDetectSettings = () => {
autoDetectSettingContainer.style = `
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
`;
autoDetectSettingContainer.innerHTML = '';
// 创建并定义解释文字的DOM元素
const explanationText = document.createElement('div');
explanationText.innerText = '🔎自动调整悬浮窗颜色(忽略上方修改)';
explanationText.style = 'margin-bottom: 10px; display: block; width: 100%; text-align: left;';
autoDetectSettingContainer.appendChild(explanationText);
// 创建自动检测设置按钮
const settingsContainer = document.createElement('div');
settingsContainer.style = 'display: flex; justify-content: space-between; width: 80%;';
settingsContainer.appendChild(createAutoDetectSetting('关闭', autoDetectMode, '关闭'));
settingsContainer.appendChild(createAutoDetectSetting('同色', autoDetectMode, '同色'));
settingsContainer.appendChild(createAutoDetectSetting('反色', autoDetectMode, '反色'));
autoDetectSettingContainer.appendChild(settingsContainer);
};
const layoutSetting = createSetting('↕️竖向排列按钮', isVerticalLayout, () => {
isVerticalLayout = !isVerticalLayout;
layoutSetting.lastChild.innerText = isVerticalLayout ? '✔️' : '✖️';
});
const createPercentageInput = (labelText, value, min, max) => {
const container = document.createElement('div');
container.style = `
display: flex;
justify-content: space-between;
width: 100%;
margin-bottom: 10px;
`;
const label = document.createElement('label');
label.innerText = labelText;
container.appendChild(label);
const input = document.createElement('input');
input.type = 'number';
input.value = value;
input.min = min;
input.max = max;
input.style = `
width: 50px;
background-color: ${isBlackMode ? 'black' : 'white'};
color: ${isBlackMode ? 'white' : 'black'};
`;
const percentageLabel = document.createElement('span');
percentageLabel.innerText = '%';
container.appendChild(input);
container.appendChild(percentageLabel);
return { container, input };
};
const sizeInput = createPercentageInput('📏悬浮窗大小', floatWindowSize, 20, 100);
const percentageInput = createPercentageInput('📄保留页面比例', reservedHeightPercentage, 0, 100);
const windowOpacityInput = createPercentageInput('🌫️窗口透明度', windowOpacity * 100, 20, 100);
const textOpacityInput = createPercentageInput('🖋️文字透明度', textOpacity * 100, 20, 100);
const saveButton = document.createElement('button');
saveButton.innerHTML = '💾保存';
saveButton.style = `
margin-top: 10px;
background-color: ${isBlackMode ? 'black' : 'white'};
color: ${isBlackMode ? 'white' : 'black'};
`;
saveButton.onclick = () => {
floatWindowSize = parseInt(sizeInput.input.value, 10);
reservedHeightPercentage = Math.min(100, Math.max(0, parseInt(percentageInput.input.value, 10)));
windowOpacity = Math.min(1, Math.max(0.2, parseFloat(windowOpacityInput.input.value) / 100));
textOpacity = Math.min(1, Math.max(0.2, parseFloat(textOpacityInput.input.value) / 100));
GM_setValue('floatWindowSize', floatWindowSize);
GM_setValue('isVerticalLayout', isVerticalLayout);
GM_setValue('reservedHeightPercentage', reservedHeightPercentage);
GM_setValue('windowOpacity', windowOpacity);
GM_setValue('textOpacity', textOpacity);
document.body.removeChild(settingsWindow);
location.reload();
};
const donateButton = document.createElement('button');
donateButton.innerHTML = '🔄更新/💰打赏';
donateButton.style = `
margin-top: 10px;
background-color: ${isBlackMode ? 'black' : 'white'};
color: ${isBlackMode ? 'white' : 'black'};
`;
donateButton.onclick = () => {
if (confirm('⚠️一部分脚本管理器无法自动检测脚本是否有更新,所以需要你去看一下。\n🔄现在的版本号是:v2.1.1。\n💬如果脚本有任何问题,或者你有任何创意,都可以在脚本反馈区留言。\n📄在脚本发布页的介绍部分也放置了我的打赏二维码,\n🥤如果这个脚本帮你解决了大问题,希望你能请我喝杯奶茶哦!')) {
window.open('https://gf.qytechs.cn/zh-CN/scripts/493257', '_blank');
}
};
const toggleFloatWindow = () => {
floatWindowVisible = !floatWindowVisible;
GM_setValue('floatWindowVisible', floatWindowVisible);
document.body.removeChild(settingsWindow);
location.reload();
};
const confirmToggleFloatWindow = () => {
if (confirm('❗️确定要关闭悬浮窗吗?\n🖥️电脑端可以通过脚本管理器中的选项重新打开,\n📱若脚本管理器没有图形化界面,可以重新安装脚本。')) {
toggleFloatWindow();
}
};
const floatWindowSetting = createSetting('📴关闭悬浮窗(长按悬浮窗可以移动)', false, confirmToggleFloatWindow);
// 分割线
const createSeparator = () => {
const separator = document.createElement('hr');
separator.style = 'width: 100%; margin: 10px 0; border: none; border-top: 1px solid #ccc;';
return separator;
};
settingsContainer.appendChild(modeSetting);
const hotkeysToggleSetting = createSetting('开启翻页热键功能', enableHotkeys, () => {
enableHotkeys = !enableHotkeys;
hotkeysToggleSetting.lastChild.innerText = enableHotkeys ? '✔️' : '✖️';
GM_setValue('enableHotkeys', enableHotkeys);
});
const autoDetectSettingContainer = document.createElement('div');
settingsContainer.appendChild(autoDetectSettingContainer);
updateAutoDetectSettings();
settingsContainer.appendChild(createSeparator());
settingsContainer.appendChild(layoutSetting);
settingsContainer.appendChild(sizeInput.container);
settingsContainer.appendChild(percentageInput.container);
settingsContainer.appendChild(windowOpacityInput.container);
settingsContainer.appendChild(textOpacityInput.container);
settingsContainer.appendChild(floatWindowSetting);
settingsContainer.appendChild(createSeparator());
const hotkeySetting = createSetting('🎛️设置电脑端翻页热键', false, () => {
const hotkeyWindow = document.createElement('div');
hotkeyWindow.style = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
background-color: ${isBlackMode ? 'black' : 'white'};
color: ${isBlackMode ? 'white' : 'black'};
border: 1px solid #ccc;
z-index: 10002;
padding: 20px;
border-radius: 5px;
`;
const hotkeyContainer = document.createElement('div');
hotkeyContainer.style = `
display: flex;
flex-direction: column;
align-items: flex-start;
color: ${isBlackMode ? 'white' : 'black'};
`;
// 创建并定义解释文字的DOM元素
const explanationText = document.createElement('div');
explanationText.innerText = '💬请设置翻页热键\n💡选中文本框后直接按下目标热键试试吧:';
explanationText.style = 'margin-bottom: 10px; display: block; width: 100%;';
hotkeyWindow.appendChild(explanationText);
const createHotkeySetting = (labelText, currentKey, onKeyChange) => {
const container = document.createElement('div');
container.style = `
display: flex;
justify-content: space-between;
width: 100%;
margin-bottom: 10px;
`;
const label = document.createElement('label');
label.innerText = labelText;
container.appendChild(label);
const input = document.createElement('input');
input.type = 'text';
input.value = currentKey;
input.style = `
width: 100px;
background-color: ${isBlackMode ? 'black' : 'white'};
color: ${isBlackMode ? 'white' : 'black'};
`;
input.onkeydown = (event) => {
event.preventDefault();
input.value = event.key;
onKeyChange(event.key);
};
container.appendChild(input);
return container;
};
const upKeySetting = createHotkeySetting('上翻页热键', upKey, (key) => { upKey = key; });
const downKeySetting = createHotkeySetting('下翻页热键', downKey, (key) => { downKey = key; });
const hotkeySaveButton = document.createElement('button');
hotkeySaveButton.innerHTML = '💾保存';
hotkeySaveButton.style = `
margin-top: 10px;
background-color: ${isBlackMode ? 'black' : 'white'};
color: ${isBlackMode ? 'white' : 'black'};
`;
hotkeySaveButton.onclick = () => {
GM_setValue('upKey', upKey);
GM_setValue('downKey', downKey);
document.body.removeChild(hotkeyWindow);
};
hotkeyContainer.appendChild(upKeySetting);
hotkeyContainer.appendChild(downKeySetting);
hotkeyContainer.appendChild(hotkeySaveButton);
hotkeyWindow.appendChild(hotkeyContainer);
document.body.appendChild(hotkeyWindow);
});
settingsContainer.appendChild(hotkeysToggleSetting);
settingsContainer.appendChild(hotkeySetting);
// 创建按钮容器
const buttonContainer = document.createElement('div');
buttonContainer.style = `
display: flex;
justify-content: space-between;
width: 100%;
margin-top: 10px;
`;
// 修改保存按钮的样式并添加到按钮容器中
saveButton.style = `
flex: 1;
margin-right: 10px;
background-color: ${isBlackMode ? 'black' : 'white'};
color: ${isBlackMode ? 'white' : 'black'};
`;
buttonContainer.appendChild(saveButton);
// 修改检查更新/打赏按钮的样式并添加到按钮容器中
donateButton.style = `
flex: 1;
background-color: ${isBlackMode ? 'black' : 'white'};
color: ${isBlackMode ? 'white' : 'black'};
`;
buttonContainer.appendChild(donateButton);
// 将按钮容器添加到设置窗口中
settingsContainer.appendChild(buttonContainer);
settingsWindow.appendChild(settingsContainer);
document.body.appendChild(settingsWindow);
updateColors();
}
// 创建并显示悬浮窗
createFloatingWindow();
// 注册(不可用)菜单命令
GM_registerMenuCommand('显示悬浮窗', function () {
GM_setValue('floatWindowVisible', true);
location.reload();
});
// 样式辅助函数
function buttonStyle() {
return `
width: ${floatWindowSize}px;
height: ${floatWindowSize}px;
font-size: 20px;
background-color: ${isBlackMode ? 'black' : 'white'};
color: ${isBlackMode ? 'white' : 'black'};
border: none;
opacity: ${textOpacity};
`;
}
})();