// ==UserScript== // @name Website Element Blocker (Long-press to block) // @name:zh-CN 网页元素屏蔽器 (长按屏蔽) // @namespace http://tampermonkey.net/ // @version 1.5 // @description Long-press on an element on your phone to bring up a menu to block it. Remembers your choices. // @description:zh-CN 在手机上长按一个元素,会弹出一个菜单来屏蔽它。可以记住你的选择。 // @author Your AI Assistant // @match *://*/* // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_addStyle // @downloadURL none // ==/UserScript== (function() { 'use strict'; // --- 配置 --- const LONG_PRESS_DURATION = 500; // 长按时长 (毫秒) const STORAGE_KEY_PREFIX = 'element_blocker_'; let pressTimer = null; let longPressFired = false; let targetElement = null; let animationIntervalId = null; // 用于存储 setInterval 的 ID // --- 样式注入 --- GM_addStyle(` .blocker-highlight { position: relative !important; z-index: 2147483646 !important; } .blocker-highlight::before { content: ''; position: absolute; top: -4px; left: -4px; right: -4px; bottom: -4px; border-radius: 4px; z-index: 2147483645; animation: blocker-rainbow-border 2s linear infinite; pointer-events: none; } @keyframes blocker-rainbow-border { 0% { box-shadow: 0 0 0 4px rgba(255, 0, 0, 0.8); } 16% { box-shadow: 0 0 0 4px rgba(255, 127, 0, 0.8); } 33% { box-shadow: 0 0 0 4px rgba(255, 255, 0, 0.8); } 50% { box-shadow: 0 0 0 4px rgba(0, 255, 0, 0.8); } 66% { box-shadow: 0 0 0 4px rgba(0, 0, 255, 0.8); } 83% { box-shadow: 0 0 0 4px rgba(75, 0, 130, 0.8); } 100% { box-shadow: 0 0 0 4px rgba(143, 0, 255, 0.8); } } #blocker-menu { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background-color: #333; color: white; padding: 10px; border-radius: 8px; z-index: 2147483647 !important; display: flex; flex-direction: column; gap: 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.4); font-family: sans-serif; font-size: 16px; } #blocker-menu button { background-color: #555; color: white; border: none; padding: 10px 15px; border-radius: 5px; cursor: pointer; text-align: center; } #blocker-menu button:hover { background-color: #777; } `); // --- 核心功能 --- function getCssSelector(el) { if (!(el instanceof Element)) return; const path = []; while (el.nodeType === Node.ELEMENT_NODE) { let selector = el.nodeName.toLowerCase(); if (el.id) { selector += `#${el.id}`; path.unshift(selector); break; } else { let sib = el, nth = 1; while (sib.previousElementSibling) { sib = sib.previousElementSibling; if (sib.nodeName.toLowerCase() == selector) nth++; } if (nth != 1) selector += `:nth-of-type(${nth})`; } path.unshift(selector); el = el.parentNode; } return path.join(' > '); } function showBlockMenu(el) { // 移除旧菜单 const oldMenu = document.getElementById('blocker-menu'); if (oldMenu) oldMenu.remove(); const menu = document.createElement('div'); menu.id = 'blocker-menu'; let currentEl = el; let level = 0; const createButton = (elem, text) => { const button = document.createElement('button'); button.textContent = text; button.onclick = (e) => { e.stopPropagation(); blockElement(elem); hideBlockMenu(); }; button.onmouseover = () => highlightElement(elem); button.onmouseout = () => highlightElement(targetElement); return button; }; // 添加 "屏蔽当前" 按钮 menu.appendChild(createButton(currentEl, `屏蔽当前 (${currentEl.tagName.toLowerCase()})`)); // 添加 "屏蔽上层" 按钮 (最多5层) while (currentEl.parentElement && level < 5) { currentEl = currentEl.parentElement; if (currentEl.tagName.toLowerCase() === 'body' || currentEl.tagName.toLowerCase() === 'html') break; level++; menu.appendChild(createButton(currentEl, `屏蔽上${level}层 (${currentEl.tagName.toLowerCase()})`)); } const cancelButton = document.createElement('button'); cancelButton.textContent = '取消'; cancelButton.style.backgroundColor = '#800'; cancelButton.onclick = hideBlockMenu; menu.appendChild(cancelButton); document.body.appendChild(menu); highlightElement(el); } function hideBlockMenu() { const menu = document.getElementById('blocker-menu'); if (menu) menu.remove(); unhighlightAll(); } function highlightElement(el) { unhighlightAll(); if(el) el.classList.add('blocker-highlight'); } function unhighlightElement(el) { if(el) el.classList.remove('blocker-highlight'); } function unhighlightAll() { document.querySelectorAll('.blocker-highlight').forEach(e => e.classList.remove('blocker-highlight')); } function blockElement(el) { const selector = getCssSelector(el); if (!selector) return; const hostname = window.location.hostname; const key = STORAGE_KEY_PREFIX + hostname; const blockedSelectors = GM_getValue(key, []); if (!blockedSelectors.includes(selector)) { blockedSelectors.push(selector); GM_setValue(key, blockedSelectors); applyBlocking(hostname); console.log(`[Element Blocker] 已屏蔽: ${selector}`); } } function applyBlocking(hostname) { const key = STORAGE_KEY_PREFIX + hostname; const selectors = GM_getValue(key, []); if (selectors.length > 0) { let style = document.getElementById('dynamic-blocker-style'); if (!style) { style = document.createElement('style'); style.id = 'dynamic-blocker-style'; document.head.appendChild(style); } style.textContent = `${selectors.join(', ')} { display: none !important; }`; console.log(`[Element Blocker] 已应用 ${selectors.length} 条屏蔽规则于 ${hostname}`); } } function clearBlockingRules() { const hostname = window.location.hostname; const key = STORAGE_KEY_PREFIX + hostname; GM_setValue(key, []); const style = document.getElementById('dynamic-blocker-style'); if (style) style.textContent = ''; alert(`已清除网站 [${hostname}] 的所有屏蔽规则。`); } // --- 事件监听 --- function onTouchStart(e) { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) { return; } longPressFired = false; targetElement = e.target; pressTimer = window.setTimeout(() => { longPressFired = true; e.preventDefault(); showBlockMenu(targetElement); }, LONG_PRESS_DURATION); } function onTouchEnd(e) { clearTimeout(pressTimer); } function onTouchMove(e) { clearTimeout(pressTimer); } // 绑定事件 window.addEventListener('touchstart', onTouchStart, { passive: false }); window.addEventListener('touchend', onTouchEnd); window.addEventListener('touchmove', onTouchMove); // --- 页面加载时应用规则 & 注册菜单 --- applyBlocking(window.location.hostname); GM_registerMenuCommand('清除当前网站的屏蔽规则', clearBlockingRules); })();