在手机上长按一个元素,会弹出一个菜单来屏蔽它。可以记住你的选择。
当前为
// ==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
// ==/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);
})();