针对墨水屏的优化 适合电纸书省电 看漫画 ①可消除移动动画(松手才移动页面) ②可设置双击放大复原 ③可屏蔽长按图片弹出的菜单
// ==UserScript==
// @name 墨水屏电纸书优化
// @namespace cc.cxuan.books
// @version 1.32
// @description 针对墨水屏的优化 适合电纸书省电 看漫画 ①可消除移动动画(松手才移动页面) ②可设置双击放大复原 ③可屏蔽长按图片弹出的菜单
// @match *://*/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @run-at document-end
// @noframes
// @license MIT
// @author cxuan.cc
// ==/UserScript==
(function(){
// 设置项
let my = GM_getValue('multiplierY', 2.5);
let mx = 2;
let intervalSec = GM_getValue('interval', 0.3);
let doubleClickZoom = GM_getValue('doubleClickZoom', 2);
let enableMx = GM_getValue('enableMx', false);
let enableParent = GM_getValue('enableParent', false);
let blockContextMenu = GM_getValue('blockContextMenu', false);
function updateSettings({key, value}) {
// 更新本地变量
switch (key) {
case 'multiplierY': my = value; break;
case 'interval':
intervalSec = value;
stopTimer(); startTimer();
break;
case 'doubleClickZoom': doubleClickZoom = value; applyViewport(); break;
case 'enableMx': enableMx = value; break;
case 'enableParent': enableParent = value; break;
case 'blockContextMenu': blockContextMenu = value; applyContextMenuBlock(); break;
}
if(key === 'doubleClickZoom') applyViewport();
}
GM_registerMenuCommand(`设置Y轴移动倍率(之前 ${my})`, ()=>{
let v = parseFloat(prompt('Y 轴滑动倍率:', my));
if (!isNaN(v)) {
GM_setValue('multiplierY', v);
updateSettings({key:'multiplierY', value:v});
}
});
GM_registerMenuCommand(`设置更新间隔(之前 ${intervalSec}s)`, ()=>{
let v = parseFloat(prompt('更新间隔(秒,0=仅松手时刷新):', intervalSec));
if (!isNaN(v)) {
GM_setValue('interval', v);
updateSettings({key:'interval', value:v});
}
});
GM_registerMenuCommand(`设置双击放大倍率(之前 ${doubleClickZoom})`, ()=>{
let v = parseFloat(prompt('双击放大倍率(0=无双击放大):', doubleClickZoom));
if (!isNaN(v)) {
GM_setValue('doubleClickZoom', v);
updateSettings({key:'doubleClickZoom', value:v});
}
});
GM_registerMenuCommand(`切换x轴移动优化开关 固定${mx}倍(之前 ${enableMx ? '开' : '关'})`, ()=>{
let v = !enableMx;
GM_setValue('enableMx', v);
updateSettings({key:'enableMx', value:v});
});
GM_registerMenuCommand(`切换父元素一同滚动(之前 ${enableParent ? '开' : '关'})`, ()=>{
let v = !enableParent;
GM_setValue('enableParent', v);
updateSettings({key:'enableParent', value:v});
});
GM_registerMenuCommand(`切换右键菜单屏蔽(之前 ${blockContextMenu ? '开' : '关'})`, ()=>{
let v = !blockContextMenu;
GM_setValue('blockContextMenu', v);
updateSettings({key:'blockContextMenu', value:v});
});
//开启或禁止双指缩放
let meta = document.querySelector('meta[name=viewport]');
const vp = 'width=device-width, initial-scale=1, minimum-scale=0.25, maximum-scale=10, user-scalable=yes';
const applyViewport = ()=>{
let head = document.head || document.getElementsByTagName('head')[0] || document.documentElement;
if(doubleClickZoom > 0){
if (meta) {
meta.setAttribute('content', vp);
} else {
meta = document.createElement('meta');
meta.name = 'viewport';
meta.content = vp;
document.head.appendChild(meta);
}
}else{
if (meta) {
meta.setAttribute('content', vp);
}
}
head.prepend(meta);
};
applyViewport();
// 右键菜单屏蔽函数
let contextMenuHandler = function(e) {
if (!e.target.closest('a')) e.preventDefault();
};
function applyContextMenuBlock() {
document.removeEventListener('contextmenu', contextMenuHandler, true);
if (blockContextMenu) {
document.addEventListener('contextmenu', contextMenuHandler, true);
}
}
applyContextMenuBlock();
const initialZoom = parseFloat(document.body.style.zoom) || 1;
const touchMap = {}; // id -> { sx, sy, cx, cy, el, lastDx, lastDy }
let timerId = null;
function periodicUpdate() {
for (let id in touchMap) {
const info = touchMap[id];
if (info.cx == null || info.cy == null) continue;
let totalDx = (info.sx - info.cx) * mx;
let totalDy = (info.sy - info.cy) * my;
let dX = totalDx - (info.lastDx || 0);
let dY = totalDy - (info.lastDy || 0);
if (enableParent) {
let node = info.el;
while (node) {
if (dX) node.scrollLeft += dX;
if (dY) node.scrollTop += dY;
node = node.parentNode;
}
} else {
if (dX) info.el.scrollLeft += dX;
if (dY) info.el.scrollTop += dY;
}
info.lastDx = totalDx;
info.lastDy = totalDy;
}
}
function startTimer(){
if (intervalSec > 0 && !timerId) {
timerId = setInterval(periodicUpdate, intervalSec * 1000);
}
}
function stopTimer(){
if (timerId) {
clearInterval(timerId);
timerId = null;
}
}
document.addEventListener('touchstart', e=>{
if (e.touches.length > 1) return;
for (const t of e.changedTouches) {
let el = t.target;
while (el && el !== document) {
const style = getComputedStyle(el);
const canScrollY = el.scrollHeight > el.clientHeight && /auto|scroll/.test(style.overflowY);
const canScrollX = el.scrollWidth > el.clientWidth && /auto|scroll/.test(style.overflowX);
if (canScrollY || canScrollX) break;
el = el.parentNode;
}
if (!el || el === document) {
el = document.scrollingElement || document.documentElement;
}
touchMap[t.identifier] = {
sx: t.clientX, sy: t.clientY,
cx: t.clientX, cy: t.clientY,
el,
lastDx: 0, lastDy: 0
};
}
startTimer();
}, { passive:false });
document.addEventListener('touchmove', e=>{
if (e.touches.length > 1) return;
let doPrevent = false;
for (const t of e.changedTouches) {
const info = touchMap[t.identifier];
if (!info) continue;
info.cx = t.clientX;
info.cy = t.clientY;
// 允许顶部下拉刷新
if (!(info.el === (document.scrollingElement || document.documentElement)
&& info.el.scrollTop === 0
&& (t.clientY - info.sy) > 0)) {
doPrevent = true;
}
// 主要横向移动
if(!enableMx){
if (Math.abs(info.cx - info.sx) > Math.abs(info.cy - info.sy) * 2){
doPrevent = false;
}
}
}
if (doPrevent) e.preventDefault();
}, { passive:false });
function finishTouch(e) {
if (e.touches.length > 1) return;
for (const t of e.changedTouches) {
const info = touchMap[t.identifier];
if (!info) continue;
if (intervalSec === 0) {
let dx = (info.sx - t.clientX) * mx;
let dy = (info.sy - t.clientY) * my;
info.el.scrollLeft += dx;
info.el.scrollTop += dy;
} else {
info.cx = t.clientX;
info.cy = t.clientY;
periodicUpdate();
}
delete touchMap[t.identifier];
}
if (Object.keys(touchMap).length === 0) stopTimer();
}
document.addEventListener('touchend', finishTouch, { passive:false });
document.addEventListener('touchcancel', finishTouch, { passive:false });
// 用 viewport 实现双击复位
let lastTap = 0;
let isDoubleClickZoomBig = false;
document.addEventListener('touchend', e=>{
if (doubleClickZoom == 0) return;
// 仅单指
if (e.touches.length === 0 && e.changedTouches.length === 1) {
let now = Date.now();
if (now - lastTap < 300) {
// 修改或插入 viewport
let meta = document.querySelector('meta[name=viewport]');
isDoubleClickZoomBig = !isDoubleClickZoomBig;
const vp = `width=device-width, initial-scale=${isDoubleClickZoomBig ? doubleClickZoom : 1}, maximum-scale=10`;
if (meta) {
meta.setAttribute('content', vp);
} else {
meta = document.createElement('meta');
meta.name = 'viewport';
meta.content = vp;
document.head.appendChild(meta);
}
}
lastTap = now;
}
}, { passive:true });
})();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址