// ==UserScript== // @name 移动端开发者工具 // @namespace http://tampermonkey.net/ // @version 0.2 // @description 移动浏览器开发者调试工具,优化网络监控 // @author Your name // @match *://*/* // @grant none // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 样式定义 const styles = ` .devtools-container { position: fixed; top: 0; left: 0; right: 0; height: 50%; background: #fff; z-index: 10000; border-bottom: 1px solid #ccc; display: none; flex-direction: column; font-family: Arial, sans-serif; transition: transform 0.3s ease; transform: translateY(-100%); } .devtools-container.expanded { transform: translateY(0); } .devtools-header { display: flex; padding: 5px; border-bottom: 1px solid #ccc; background: #f5f5f5; } .devtools-tab { padding: 5px 10px; margin-right: 5px; cursor: pointer; border: 1px solid #ccc; border-radius: 3px; font-size: 14px; } .devtools-tab.active { background: #fff; border-bottom: none; } .devtools-content { flex: 1; overflow: auto; padding: 10px; } .devtools-panel { display: none; height: 100%; } .devtools-panel.active { display: block; } .toggle-devtools { position: fixed; top: 10px; right: 10px; z-index: 10001; padding: 5px 10px; background: #4CAF50; color: white; border: none; border-radius: 3px; cursor: pointer; font-size: 14px; box-shadow: 0 2px 5px rgba(0,0,0,0.2); } .expand-collapse { position: absolute; bottom: -20px; left: 50%; transform: translateX(-50%); background: #4CAF50; color: white; border: none; border-radius: 0 0 5px 5px; padding: 2px 10px; cursor: pointer; z-index: 10001; } .element-highlight { position: absolute; background: rgba(137, 196, 244, 0.3); border: 1px solid #89C4F4; pointer-events: none; z-index: 9999; } .console-input { width: 100%; padding: 5px; border: 1px solid #ccc; } .console-output { margin: 5px 0; padding: 5px; background: #f5f5f5; border-radius: 3px; } .network-item { padding: 10px; border-bottom: 1px solid #eee; cursor: pointer; } .network-item:hover { background-color: #f0f0f0; } .network-details { display: none; padding: 10px; background: #f9f9f9; margin-top: 5px; border-radius: 4px; } .network-item.expanded .network-details { display: block; } .network-summary { display: flex; justify-content: space-between; } .network-summary > div { margin-right: 10px; } .network-details pre { white-space: pre-wrap; word-wrap: break-word; background: #fff; padding: 8px; border-radius: 4px; border: 1px solid #eee; margin: 5px 0; max-height: 300px; overflow-y: auto; } `; // 添加样式 function addStyle(css) { const style = document.createElement('style'); style.textContent = css; document.head.appendChild(style); } // 创建开发者工具UI function createDevToolsUI() { const container = document.createElement('div'); container.className = 'devtools-container'; container.innerHTML = `
${element.outerHTML}
${JSON.stringify(window.getComputedStyle(element), null, 2)}`; } document.addEventListener('mousemove', (e) => { if (!elementsPanel.classList.contains('active')) return; const element = document.elementFromPoint(e.clientX, e.clientY); if (element && !element.closest('.devtools-container')) { updateHighlight(element); highlight.style.display = 'block'; } }); document.addEventListener('click', (e) => { if (!elementsPanel.classList.contains('active')) return; const element = document.elementFromPoint(e.clientX, e.clientY); if (element && !element.closest('.devtools-container')) { e.preventDefault(); showElementInfo(element); } }); } // 控制台功能 function initConsole(consolePanel) { const input = consolePanel.querySelector('.console-input'); const outputContainer = consolePanel.querySelector('.console-output-container'); function log(message, type = 'log') { const output = document.createElement('div'); output.className = `console-output ${type}`; output.textContent = message; outputContainer.appendChild(output); outputContainer.scrollTop = outputContainer.scrollHeight; } const originalConsole = { log: console.log, error: console.error, warn: console.warn }; console.log = function(...args) { log(args.join(' ')); originalConsole.log.apply(console, args); }; console.error = function(...args) { log(args.join(' '), 'error'); originalConsole.error.apply(console, args); }; console.warn = function(...args) { log(args.join(' '), 'warn'); originalConsole.warn.apply(console, args); }; input.addEventListener('keypress', (e) => { if (e.key === 'Enter') { try { const result = eval(input.value); log(`> ${input.value}`); log(result); } catch (error) { log(error.message, 'error'); } input.value = ''; } }); } // 网络请求监控 function initNetworkMonitor(networkPanel) { const originalFetch = window.fetch; const originalXHR = window.XMLHttpRequest.prototype.open; function formatHeaders(headers) { if (headers instanceof Headers) { return Array.from(headers.entries()) .map(([key, value]) => `${key}: ${value}`) .join('\n'); } else if (typeof headers === 'string') { // 处理XMLHttpRequest的getAllResponseHeaders()返回的字符串 return headers.split('\r\n').filter(line => line.trim()).join('\n'); } else if (headers && typeof headers === 'object') { return Object.entries(headers) .map(([key, value]) => `${key}: ${value}`) .join('\n'); } return 'No headers available'; } function formatBody(body, contentType) { if (contentType && contentType.includes('application/json')) { try { return JSON.stringify(JSON.parse(body), null, 2); } catch (e) { return body; } } return body; } function createNetworkLogItem(requestInfo, responseInfo) { const item = document.createElement('div'); item.className = 'network-item'; item.innerHTML = `
Request URL: ${requestInfo.url} Request Method: ${requestInfo.method} Status Code: ${responseInfo.status} Remote Address: ${location.hostname} Referrer Policy: ${document.referrer}
${formatHeaders(responseInfo.headers)}
${formatHeaders(requestInfo.headers)}
${formatBody(responseInfo.body, responseInfo.headers['content-type'] || responseInfo.headers.get('content-type'))}
${rules.map(rule => rule.cssText).join('\n')}
无法访问样式表 ${index + 1} (CORS限制)
`; } }); stylesPanel.innerHTML = html; } updateStyles(); } // 初始化开发者工具 function initDevTools() { addStyle(styles); const {container, toggleButton} = createDevToolsUI(); const elementsPanel = container.querySelector('.elements-panel'); const consolePanel = container.querySelector('.console-panel'); const networkPanel = container.querySelector('.network-panel'); const stylesPanel = container.querySelector('.styles-panel'); const expandCollapseBtn = container.querySelector('.expand-collapse'); initElementInspector(elementsPanel); initConsole(consolePanel); initNetworkMonitor(networkPanel); initStylesPanel(stylesPanel); // 标签切换 container.querySelector('.devtools-header').addEventListener('click', (e) => { if (e.target.classList.contains('devtools-tab')) { const panelName = e.target.dataset.panel; container.querySelectorAll('.devtools-tab').forEach(tab => tab.classList.remove('active')); container.querySelectorAll('.devtools-panel').forEach(panel => panel.classList.remove('active')); e.target.classList.add('active'); container.querySelector(`.${panelName}-panel`).classList.add('active'); } }); // 展开/收起面板 expandCollapseBtn.addEventListener('click', () => { container.classList.toggle('expanded'); expandCollapseBtn.textContent = container.classList.contains('expanded') ? '收起' : '展开'; }); // 显示/隐藏开发者工具 toggleButton.addEventListener('click', () => { container.style.display = container.style.display === 'none' ? 'flex' : 'none'; if (container.style.display === 'flex') { container.classList.add('expanded'); expandCollapseBtn.textContent = '收起'; } }); } // 页面加载完成后初始化 window.addEventListener('load', initDevTools); })();