Luogu 题目难度隐藏插件 V1.3
LTTXiaochuan · · 科技·工程
插件介绍:
写题或 VP 模拟赛时我们经常会不小心看到题目难度,从而大致猜出题目所使用的算法,导致直接跳过或者不屑于做 很不利于提升我们的判题水平。于是乎做了一个小插件,能够一键隐藏题目难度,切换悬停显示/显示/隐藏三种模式。希望能够帮到同志们。
有了这个插件妈妈再也不用担心我不会对着黑题傻想俩小时了
使用说明:
此为篡改猴脚本,需先安装篡改猴方可使用。具体安装方式与安装一般的篡改猴脚本相同(如是 MSEdge 用户请在扩展中打开“开发人员模式”)。网上教程诸多,这里不再赘述。
更新日志:
【2025.8.21】正式发布 V1.2!
【2025.8.21】发布 V1.3,修复了手残把按钮拖到页面外弄不回来的问题,修复了题单无法隐藏难度的 bug.
插件源码:
// ==UserScript==
// @name Luogu 难度隐藏开关
// @namespace http://tampermonkey.net/
// @version V1.3
// @description Luogu 题目难度标签隐藏/悬停显示/始终显示,浮动按钮可拖动、记忆位置、防止拖出屏幕、拖动时半透明。
// @author LTTXiaochuan
// @match https://www.luogu.com.cn/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
const DEFAULT_MODE = GM_getValue('lg_diff_mode', 'hover');
const selectors = [
'.l-flex-info-row a[href*="problem/list?difficulty"] span',
'.difficulty span span',
'.difficulty span.lfe-caption'
];
const styleId = 'tm-luogu-diff-style';
const css = `
.tm-diff-hidden, .tm-diff-hover { transition: opacity .15s ease !important; }
.tm-diff-hidden { opacity: 0 !important; }
.tm-diff-hover { opacity: 0 !important; }
.tm-diff-hover:hover { opacity: 1 !important; }
#tm-luogu-diff-toggle {
position: fixed;
top: 12px;
right: 12px;
z-index: 999999;
background: rgba(0,0,0,0.6);
color: #fff !important;
padding: 6px 8px;
font-size: 12px;
border-radius: 6px;
cursor: move;
user-select: none;
box-shadow: 0 2px 6px rgba(0,0,0,.4);
}
#tm-luogu-diff-toggle small { opacity: .8; display:block; font-size:11px; margin-top:2px; color: #fff !important; }
`;
function injectStyle() {
if (document.getElementById(styleId)) return;
const s = document.createElement('style');
s.id = styleId;
s.textContent = css;
document.head.appendChild(s);
}
let currentMode = DEFAULT_MODE;
function applyToElement(el, mode) {
el.classList.remove('tm-diff-hidden', 'tm-diff-hover');
if (mode === 'hidden') el.classList.add('tm-diff-hidden');
else if (mode === 'hover') el.classList.add('tm-diff-hover');
}
function applyModeToAll(mode) {
const combined = selectors.join(',');
document.querySelectorAll(combined).forEach(el => applyToElement(el, mode));
}
let mo = null;
function startObserver() {
if (mo) return;
mo = new MutationObserver(muts => {
if (muts.some(m => m.addedNodes && m.addedNodes.length)) {
applyModeToAll(currentMode);
}
});
mo.observe(document.body, { childList: true, subtree: true });
}
function saveMode(mode) {
currentMode = mode;
GM_setValue('lg_diff_mode', mode);
updateToggleText();
applyModeToAll(mode);
}
function nextMode(m) {
if (m === 'show') return 'hover';
if (m === 'hover') return 'hidden';
return 'show';
}
function createToggle() {
if (document.getElementById('tm-luogu-diff-toggle')) return;
const btn = document.createElement('div');
btn.id = 'tm-luogu-diff-toggle';
btn.title = '点击切换难度显示模式';
btn.style.minWidth = '120px';
btn.style.textAlign = 'center';
btn.style.fontFamily = 'Segoe UI,微软雅黑,sans-serif';
const savedX = GM_getValue('lg_diff_x', null);
const savedY = GM_getValue('lg_diff_y', null);
if (savedX !== null && savedY !== null) {
btn.style.left = savedX + 'px';
btn.style.top = savedY + 'px';
btn.style.right = 'auto';
}
btn.addEventListener('click', (e) => {
if (btn._dragging) return;
saveMode(nextMode(currentMode));
});
makeDraggable(btn);
document.body.appendChild(btn);
updateToggleText();
}
function updateToggleText() {
const btn = document.getElementById('tm-luogu-diff-toggle');
if (!btn) return;
const label = (currentMode === 'show') ? '显示难度' : (currentMode === 'hover') ? '悬停显示难度' : '隐藏难度';
btn.innerHTML = ` <strong> ${label} </strong> <small> (点击切换) </small> `;
}
// 拖动逻辑 + 防止拖出屏幕 + 拖动时半透明
function makeDraggable(el) {
let offsetX, offsetY, isDown = false;
el.addEventListener('mousedown', (e) => {
isDown = true;
el._dragging = false;
offsetX = e.clientX - el.offsetLeft;
offsetY = e.clientY - el.offsetTop;
el.style.opacity = "0.6"; // 拖动时半透明
document.addEventListener('mousemove', move);
document.addEventListener('mouseup', up);
});
function move(e) {
if (!isDown) return;
el._dragging = true;
let newLeft = e.clientX - offsetX;
let newTop = e.clientY - offsetY;
// 限制在可视区域内
const maxLeft = window.innerWidth - el.offsetWidth;
const maxTop = window.innerHeight - el.offsetHeight;
newLeft = Math.max(0, Math.min(maxLeft, newLeft));
newTop = Math.max(0, Math.min(maxTop, newTop));
el.style.left = newLeft + 'px';
el.style.top = newTop + 'px';
el.style.right = 'auto';
}
function up() {
if (!isDown) return;
isDown = false;
el.style.opacity = "1"; // 拖动结束恢复
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', up);
GM_setValue('lg_diff_x', el.offsetLeft);
GM_setValue('lg_diff_y', el.offsetTop);
setTimeout(() => { el._dragging = false; }, 50);
}
}
function init() {
injectStyle();
createToggle();
applyModeToAll(currentMode);
startObserver();
window.addEventListener('load', () => setTimeout(() => applyModeToAll(currentMode), 300));
}
init();
})();