// ==UserScript==
// @name 长按删除网页元素(v1.4 修复菜单闪退)
// @namespace custom-longpress-delete
// @version 1.4
// @description 安卓浏览器长按弹菜单:删除/取消,带高亮,点击外部关闭,修复菜单闪一下就消失的问题。
// @match *://*/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
const LONGPRESS_DELAY = 600;
const MAX_Z = 2147483647;
let longPressTimer = null;
let pressedElement = null;
let originalStyles = new WeakMap();
let menuVisible = false;
let touchActive = false;
// ===== 菜单 =====
const menu = document.createElement('div');
Object.assign(menu.style, {
position: 'fixed',
display: 'none',
padding: '10px 14px',
borderRadius: '10px',
background: 'rgba(0,0,0,0.88)',
color: '#fff',
fontSize: '16px',
zIndex: String(MAX_Z),
userSelect: 'none',
boxShadow: '0 6px 18px rgba(0,0,0,0.35)',
minWidth: '130px',
textAlign: 'center',
transform: 'translate(-50%, -120%)'
});
const delBtn = document.createElement('div');
delBtn.innerText = '删除元素';
delBtn.style.padding = '8px 0';
delBtn.style.cursor = 'pointer';
delBtn.onclick = e => {
e.stopPropagation();
if (pressedElement) pressedElement.remove();
hideMenu();
};
const cancelBtn = document.createElement('div');
cancelBtn.innerText = '取消';
cancelBtn.style.padding = '8px 0';
cancelBtn.style.cursor = 'pointer';
cancelBtn.style.marginTop = '6px';
cancelBtn.style.borderTop = '1px solid rgba(255,255,255,0.15)';
cancelBtn.onclick = e => {
e.stopPropagation();
hideMenu();
};
menu.appendChild(delBtn);
menu.appendChild(cancelBtn);
document.body.appendChild(menu);
// ===== 显示 / 隐藏 =====
function showMenuAt(x, y) {
menu.style.left = x + 'px';
menu.style.top = y + 'px';
menu.style.display = 'block';
menuVisible = true;
}
function hideMenu() {
if (pressedElement && originalStyles.has(pressedElement)) {
const orig = originalStyles.get(pressedElement);
pressedElement.style.outline = orig.outline || '';
pressedElement.style.outlineOffset = orig.outlineOffset || '';
originalStyles.delete(pressedElement);
}
pressedElement = null;
menu.style.display = 'none';
menuVisible = false;
}
// ===== 事件绑定 =====
document.addEventListener('touchstart', e => {
if (e.target.closest('#longpress-menu')) return;
touchActive = true;
pressedElement = e.target;
const touch = e.touches[0];
const x = touch.clientX;
const y = touch.clientY;
longPressTimer = setTimeout(() => {
if (!pressedElement) return;
// 保存并高亮
originalStyles.set(pressedElement, {
outline: pressedElement.style.outline || '',
outlineOffset: pressedElement.style.outlineOffset || ''
});
pressedElement.style.outline = '3px solid rgba(255,0,0,0.6)';
pressedElement.style.outlineOffset = '-3px';
showMenuAt(x, y);
e.preventDefault(); // 阻止原生长按菜单
}, LONGPRESS_DELAY);
}, { passive: false });
document.addEventListener('touchmove', e => {
// 移动时只取消未触发的长按
if (longPressTimer) {
clearTimeout(longPressTimer);
longPressTimer = null;
}
}, { passive: true });
document.addEventListener('touchend', e => {
touchActive = false;
clearTimeout(longPressTimer);
longPressTimer = null;
if (menuVisible) {
// 如果点击在菜单外部,就关闭
if (!e.target.closest('#longpress-menu')) {
hideMenu();
}
} else {
pressedElement = null;
}
}, { passive: true });
document.addEventListener('touchcancel', () => {
touchActive = false;
clearTimeout(longPressTimer);
longPressTimer = null;
hideMenu();
});
// 滚动时收起菜单
window.addEventListener('scroll', () => {
if (menuVisible) hideMenu();
}, { passive: true });
// 拦截 contextmenu
document.addEventListener('contextmenu', e => {
if (menuVisible) e.preventDefault();
}, true);
})();