// ==UserScript== // @name Website Element Blocker (Long-press to block) // @name:zh-CN 网页元素屏蔽器 (长按屏蔽) // @namespace http://tampermonkey.net/ // @version 1.3 // @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; // --- 样式注入 --- GM_addStyle(` .blocker-highlight { outline: 2px dashed red !important; box-shadow: 0 0 10px 5px rgba(255, 0, 0, 0.5) !important; background-color: rgba(255, 0, 0, 0.2) !important; /* 为高亮框也设置一个较高的 z-index,但要低于菜单 */ z-index: 2147483646 !important; } #blocker-menu { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background-color: #333; color: white; padding: 10px; border-radius: 8px; /* * 【关键修改】 * 将 z-index 设置为 2147483647,这是32位有符号整数的最大值。 * 这能确保菜单显示在几乎所有网页元素的最顶层。 * 同时添加 !important 规则以强制生效。 */ 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 = () => unhighlightElement(elem); 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); } // 使用 display: none !important; 来确保隐藏 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); })();