// ==UserScript==
// @name 漫画图片网站自动触发懒加载
// @namespace http://tampermonkey/auto-scroll
// @version 1.1
// @author Optimized
// @description 智能滚动触发懒加载,控制面板自动隐藏为边缘竖线,支持自动开始、速度调节、暂停/继续
// @match http://*/*
// @match https://*/*
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
// 配置项
const CONFIG = {
time: 300, // 滚动间隔(ms)
distance: 600, // 每次滚动距离(px)
bottomThreshold: 100, // 距底部阈值(px)
scrollBehavior: 'smooth', // 滚动行为
autoHideDelay: 2000, // 自动隐藏延迟(ms)
hideOffset: -145, // 隐藏时偏移量(px)
autoStart: true // 是否自动开始滚动
};
let scrollInterval = null;
let isScrolling = false;
let scrollCount = 0;
let hideTimer = null;
let isPanelVisible = true;
// 创建UI控制器
function createController() {
const container = document.createElement('div');
container.id = 'manga-scroll-controller';
container.innerHTML = `
准备就绪
`;
document.body.appendChild(container);
// 设置自动隐藏功能
setupAutoHide(container);
// 设置自动开始功能
setupAutoStart();
}
// 设置自动隐藏
function setupAutoHide(container) {
const autoHideToggle = document.getElementById('auto-hide-toggle');
// 显示面板
function showPanel() {
if (container.classList.contains('hidden')) {
container.classList.remove('hidden');
isPanelVisible = true;
}
resetHideTimer();
}
// 隐藏面板
function hidePanel() {
if (!container.matches(':hover') && autoHideToggle.checked) {
container.classList.add('hidden');
isPanelVisible = false;
}
}
// 重置隐藏计时器
function resetHideTimer() {
if (hideTimer) {
clearTimeout(hideTimer);
hideTimer = null;
}
// 如果开启了自动隐藏
if (autoHideToggle && autoHideToggle.checked) {
hideTimer = setTimeout(() => {
hidePanel();
}, CONFIG.autoHideDelay);
}
}
// 鼠标进入面板
container.addEventListener('mouseenter', () => {
if (hideTimer) {
clearTimeout(hideTimer);
hideTimer = null;
}
if (!isPanelVisible) {
showPanel();
}
});
// 鼠标离开面板
container.addEventListener('mouseleave', () => {
if (autoHideToggle && autoHideToggle.checked) {
hideTimer = setTimeout(() => {
hidePanel();
}, 500);
}
});
// 面板内交互时重置计时器
container.addEventListener('click', resetHideTimer);
container.addEventListener('input', resetHideTimer);
container.addEventListener('focusin', resetHideTimer);
// 自动隐藏开关变化
autoHideToggle.addEventListener('change', () => {
if (autoHideToggle.checked) {
resetHideTimer();
} else {
if (hideTimer) {
clearTimeout(hideTimer);
hideTimer = null;
}
container.classList.remove('hidden');
isPanelVisible = true;
}
});
// 全局鼠标移动检测
document.addEventListener('mousemove', (e) => {
if (!isPanelVisible && autoHideToggle && autoHideToggle.checked) {
if (e.clientX <= 30) {
const viewportHeight = window.innerHeight;
const triggerZoneTop = viewportHeight * 0.2;
const triggerZoneBottom = viewportHeight * 0.8;
if (e.clientY >= triggerZoneTop && e.clientY <= triggerZoneBottom) {
showPanel();
}
}
}
});
// 初始自动隐藏
if (autoHideToggle.checked) {
hideTimer = setTimeout(() => {
hidePanel();
}, CONFIG.autoHideDelay);
}
}
// 设置自动开始
function setupAutoStart() {
const autoStartToggle = document.getElementById('auto-start-toggle');
// 保存自动开始设置到本地存储
function saveAutoStartSetting(enabled) {
try {
localStorage.setItem('manga-scroll-auto-start', enabled ? 'true' : 'false');
} catch (e) {
// 忽略存储错误
}
}
// 加载自动开始设置
function loadAutoStartSetting() {
try {
const saved = localStorage.getItem('manga-scroll-auto-start');
if (saved !== null) {
return saved === 'true';
}
} catch (e) {
// 忽略存储错误
}
return CONFIG.autoStart; // 默认值
}
// 初始化自动开始状态
const savedAutoStart = loadAutoStartSetting();
autoStartToggle.checked = savedAutoStart;
CONFIG.autoStart = savedAutoStart;
// 自动开始开关变化事件
autoStartToggle.addEventListener('change', () => {
CONFIG.autoStart = autoStartToggle.checked;
saveAutoStartSetting(CONFIG.autoStart);
// 更新信息提示
if (CONFIG.autoStart) {
updateInfo('已启用自动开始');
// 如果当前没有在滚动,自动开始
if (!isScrolling) {
startScroll();
}
} else {
updateInfo('已禁用自动开始');
}
});
// 页面加载时的行为
if (CONFIG.autoStart) {
updateInfo('自动开始已启用');
} else {
updateInfo('自动开始已禁用,点击按钮开始');
}
}
// 智能滚动 - 触发懒加载
function smartScroll() {
const currentPosition = window.pageYOffset + window.innerHeight;
const documentHeight = Math.max(
document.body.scrollHeight,
document.body.offsetHeight,
document.documentElement.clientHeight,
document.documentElement.scrollHeight,
document.documentElement.offsetHeight
);
if (currentPosition + CONFIG.bottomThreshold >= documentHeight) {
setTimeout(() => {
const newHeight = Math.max(
document.body.scrollHeight,
document.documentElement.scrollHeight
);
if (newHeight <= documentHeight + CONFIG.distance) {
stopScroll();
updateInfo('已到底部,返回顶部');
setTimeout(() => {
window.scrollTo({ top: 0, behavior: 'smooth' });
}, 1000);
} else {
updateInfo(`触发懒加载,继续滚动... (${++scrollCount})`);
window.scrollBy({
top: CONFIG.distance,
behavior: CONFIG.scrollBehavior
});
}
}, 500);
} else {
window.scrollBy({
top: CONFIG.distance,
behavior: CONFIG.scrollBehavior
});
scrollCount++;
updateInfo(`滚动中... (${scrollCount}次)`);
}
}
// 更新信息显示
function updateInfo(message) {
const infoElement = document.getElementById('scroll-info');
if (infoElement) {
infoElement.textContent = message;
}
}
// 开始滚动
function startScroll() {
if (!scrollInterval) {
const time = parseInt(document.getElementById('scroll-time-input').value) || CONFIG.time;
const distance = parseInt(document.getElementById('scroll-distance-input').value) || CONFIG.distance;
CONFIG.time = time;
CONFIG.distance = distance;
smartScroll();
scrollInterval = setInterval(smartScroll, time);
isScrolling = true;
scrollCount = 0;
const btn = document.getElementById('scroll-toggle-btn');
if (btn) {
btn.textContent = '⏸ 暂停';
btn.classList.remove('paused');
}
updateInfo('开始滚动...');
}
}
// 停止滚动
function stopScroll() {
if (scrollInterval) {
clearInterval(scrollInterval);
scrollInterval = null;
isScrolling = false;
const btn = document.getElementById('scroll-toggle-btn');
if (btn) {
btn.textContent = '▶ 继续';
btn.classList.add('paused');
}
updateInfo('已暂停');
}
}
// 切换滚动状态
function toggleScroll() {
if (isScrolling) {
stopScroll();
} else {
startScroll();
}
}
// 键盘快捷键
function setupKeyboardShortcuts() {
document.addEventListener('keydown', (e) => {
if (document.activeElement.tagName === 'INPUT' ||
document.activeElement.tagName === 'TEXTAREA') {
return;
}
switch(e.key) {
case ' ':
e.preventDefault();
toggleScroll();
break;
case 'ArrowUp':
if (e.ctrlKey) {
e.preventDefault();
document.getElementById('scroll-top-btn')?.click();
}
break;
case 'ArrowDown':
if (e.ctrlKey) {
e.preventDefault();
document.getElementById('scroll-bottom-btn')?.click();
}
break;
case 'h':
if (e.ctrlKey && e.shiftKey) {
e.preventDefault();
const autoHideToggle = document.getElementById('auto-hide-toggle');
if (autoHideToggle) {
autoHideToggle.checked = !autoHideToggle.checked;
autoHideToggle.dispatchEvent(new Event('change'));
}
}
break;
case 'a':
if (e.ctrlKey && e.shiftKey) {
e.preventDefault();
const autoStartToggle = document.getElementById('auto-start-toggle');
if (autoStartToggle) {
autoStartToggle.checked = !autoStartToggle.checked;
autoStartToggle.dispatchEvent(new Event('change'));
}
}
break;
}
});
}
// 初始化
function init() {
createController();
setupKeyboardShortcuts();
document.getElementById('scroll-toggle-btn').addEventListener('click', toggleScroll);
document.getElementById('scroll-top-btn').addEventListener('click', () => {
window.scrollTo({ top: 0, behavior: 'smooth' });
});
document.getElementById('scroll-bottom-btn').addEventListener('click', () => {
window.scrollTo({
top: document.documentElement.scrollHeight,
behavior: 'smooth'
});
});
['scroll-time-input', 'scroll-distance-input'].forEach(id => {
document.getElementById(id).addEventListener('change', () => {
if (isScrolling) {
stopScroll();
startScroll();
}
});
});
window.addEventListener('beforeunload', () => {
stopScroll();
if (hideTimer) {
clearTimeout(hideTimer);
}
});
// 根据自动开始设置决定是否自动开始滚动
if (CONFIG.autoStart) {
startScroll();
} else {
// 不自动开始,但准备好界面
const btn = document.getElementById('scroll-toggle-btn');
if (btn) {
btn.textContent = '▶ 开始';
btn.classList.add('paused');
}
}
console.log('漫画懒加载滚动器已启动 | 快捷键: 空格暂停 | Ctrl+Shift+A 切换自动开始 | Ctrl+Shift+H 切换自动隐藏 | Ctrl+↑↓ 跳转');
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();