// ==UserScript==
// @name XPath工具
// @namespace http://tampermonkey.net/
// @version 1.4
// @description 按Shift+X在鼠标位置显示输入框,并提供实时反馈和高级配置选项操作XPath元素
// @author Ace
// @match https://*/*
// @grant none
// @downloadURL none
// ==/UserScript==
(function () {
'use strict';
let toolbar = null;
let currentElement = null;
let isShiftPressed = false;
let originalBackgroundColor = '';
const SHOW_KEY = 'KeyX';
const SELECT_KEY = 'ShiftLeft';
function getXPath(element) {
if (element.id) {
return `//*[@id="${element.id}"]`;
}
if (element === document.body) {
return '/html/body';
}
let ix = 0;
const siblings = element.parentNode.childNodes;
for (let i = 0; siblings[i]; i++) {
const sibling = siblings[i];
if (sibling === element) {
return `${getXPath(element.parentNode)}/${element.tagName.toLowerCase()}[${ix + 1}]`;
}
if (sibling.nodeType === 1 && sibling.tagName === element.tagName) {
ix++;
}
}
}
function highlightElement(element) {
if (currentElement) {
currentElement.style.backgroundColor = originalBackgroundColor;
}
originalBackgroundColor = element.style.backgroundColor;
element.style.backgroundColor = '#FFF59D';
currentElement = element;
}
function clearHighlight() {
if (currentElement) {
currentElement.style.backgroundColor = originalBackgroundColor;
currentElement = null;
}
}
document.addEventListener('keydown', (event) => {
if (event.key === 'Shift') {
isShiftPressed = true;
}
});
document.addEventListener('keyup', (event) => {
if (event.key === 'Shift') {
isShiftPressed = false;
clearHighlight();
}
});
document.addEventListener('mouseover', (event) => {
if (isShiftPressed) {
highlightElement(event.target);
}
});
document.addEventListener('mouseout', (event) => {
if (isShiftPressed && currentElement === event.target) {
clearHighlight();
}
});
document.addEventListener('click', (event) => {
if (isShiftPressed) {
event.preventDefault();
const xpath = getXPath(event.target);
document.getElementById('custom-xpath-input').value = xpath;
}
});
function createToolbar() {
if (document.getElementById('custom-toolbar')) return;
toolbar = document.createElement('div');
toolbar.id = 'custom-toolbar';
toolbar.style.position = 'fixed';
toolbar.style.zIndex = '9999';
toolbar.style.backgroundColor = 'rgba(33, 33, 33, 0.95)';
toolbar.style.color = '#fff';
toolbar.style.padding = '15px';
toolbar.style.borderRadius = '8px';
toolbar.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
toolbar.style.display = 'none';
const input = document.createElement('input');
input.id = 'custom-xpath-input';
input.type = 'text';
input.placeholder = '输入XPath';
input.style.width = '250px';
input.style.padding = '8px';
input.style.border = '1px solid #ccc';
input.style.borderRadius = '4px';
input.style.color = '#000';
input.style.backgroundColor = '#fff';
toolbar.appendChild(input);
const button = document.createElement('button');
button.innerText = '删除';
button.style.marginLeft = '10px';
button.style.padding = '8px 12px';
button.style.backgroundColor = '#e74c3c';
button.style.color = '#fff';
button.style.border = 'none';
button.style.borderRadius = '4px';
button.style.cursor = 'pointer';
button.style.transition = 'background-color 0.3s';
button.onmouseover = function () {
button.style.backgroundColor = '#c0392b';
};
button.onmouseout = function () {
button.style.backgroundColor = '#e74c3c';
};
button.onclick = function () {
const userXPath = input.value;
if (!userXPath) {
alert('请输入XPath');
return;
}
const element = document.evaluate(
userXPath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
if (element) {
if (document.getElementById('style-checkbox').checked) {
element.style.display = 'none';
alert(`已隐藏元素: ${userXPath}`);
} else {
element.remove();
alert(`已删除元素: ${userXPath}`);
}
} else {
alert('未找到匹配的元素');
}
};
toolbar.appendChild(button);
const styleCheckbox = document.createElement('div');
styleCheckbox.innerHTML = `
`;
styleCheckbox.querySelector('input').addEventListener('change', (event) => {
button.innerText = event.target.checked ? '隐藏' : '删除';
});
toolbar.appendChild(styleCheckbox);
const highlightCheckbox = document.createElement('div');
highlightCheckbox.innerHTML = `
`;
toolbar.appendChild(highlightCheckbox);
input.addEventListener('input', () => {
if (document.getElementById('highlight-checkbox').checked) {
highlightMatchingElements(input.value);
}
});
highlightCheckbox.addEventListener('change', () => {
const userXPath = input.value;
if (highlightCheckbox.querySelector('input').checked && userXPath) {
highlightMatchingElements(userXPath);
} else {
document.querySelectorAll('.highlighted-element').forEach((el) => {
el.style.backgroundColor = '';
el.classList.remove('highlighted-element');
});
}
});
document.body.appendChild(toolbar);
function toggleToolbarAtMouse(event) {
const mouseX = event.clientX;
const mouseY = event.clientY;
toolbar.style.left = `${mouseX}px`;
toolbar.style.top = `${mouseY}px`;
toolbar.style.display = toolbar.style.display === 'none' ? 'block' : 'none';
}
document.addEventListener('keydown', (event) => {
if (event.shiftKey && event.code === 'KeyX') {
document.addEventListener('mousemove', (mouseEvent) => {
toggleToolbarAtMouse(mouseEvent);
}, { once: true });
}
});
const observer = new MutationObserver((mutations) => {
const userXPath = input.value;
if (document.getElementById('highlight-checkbox').checked && userXPath) {
highlightMatchingElements(userXPath);
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
function highlightMatchingElements(xpath) {
const elements = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
for (let i = 0; i < elements.snapshotLength; i++) {
const element = elements.snapshotItem(i);
element.style.backgroundColor = 'yellow';
element.classList.add('highlighted-element');
}
}
createToolbar();
})();