移动端网络监测套件(极简版)

轻量级网络监测工具

目前为 2025-03-04 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 移动端网络监测套件(极简版)
  3. // @namespace http://tampermonkey.net/
  4. // @version 4.0.0
  5. // @description 轻量级网络监测工具
  6. // @license MIT
  7. // @match http://*/*
  8. // @match https://*/*
  9. // @run-at document-start
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. const createShadowContainer = () => {
  17. const host = document.createElement('div');
  18. const shadowRoot = host.attachShadow({ mode: 'closed' });
  19. document.documentElement.appendChild(host);
  20. const container = document.createElement("div");
  21. Object.assign(container.style, {
  22. position: "fixed",
  23. right: "10px",
  24. bottom: "10px",
  25. display: "flex",
  26. gap: "8px",
  27. zIndex: "999998",
  28. pointerEvents: "none",
  29. flexWrap: "wrap"
  30. });
  31. shadowRoot.appendChild(container);
  32. return container;
  33. };
  34.  
  35. const container = createShadowContainer();
  36. let resourceObserver, updateTimer, scrollTimer;
  37.  
  38. const panelStyle = {
  39. padding: "5px 10px",
  40. background: "rgba(40, 40, 40, 0.9)",
  41. color: "#f0f0f0",
  42. borderRadius: "8px",
  43. fontSize: "12px",
  44. fontFamily: "system-ui, sans-serif",
  45. backdropFilter: "blur(4px)",
  46. boxShadow: "0 1px 3px rgba(0,0,0,0.1)",
  47. whiteSpace: "nowrap",
  48. transition: "opacity 0.2s",
  49. flexShrink: 0
  50. };
  51.  
  52. const [trafficPanel, latencyPanel] = ['流量: 0 B', '延迟: ...'].map(text => {
  53. const panel = document.createElement("div");
  54. panel.textContent = text;
  55. Object.assign(panel.style, panelStyle);
  56. return panel;
  57. });
  58. container.append(trafficPanel, latencyPanel);
  59.  
  60. let totalBytes = 0;
  61. const formatSize = bytes => {
  62. if (bytes < 1024) return `${bytes} B`;
  63. return bytes < 1048576 ?
  64. `${(bytes/1024).toFixed(1)} KB` :
  65. `${(bytes/1048576).toFixed(2)} MB`;
  66. };
  67.  
  68. const initResourceObserver = () => {
  69. resourceObserver = new PerformanceObserver(list => {
  70. list.getEntries().forEach(entry => {
  71. const size = entry.transferSize || entry.decodedBodySize || 0;
  72. if (size > 0) totalBytes += size;
  73. });
  74. trafficPanel.textContent = `流量: ${formatSize(totalBytes)}`;
  75. });
  76. resourceObserver.observe({ type: 'resource', buffered: true });
  77. };
  78.  
  79. const getLatencyColor = latency => {
  80. if (latency < 100) return '#4caf50';
  81. if (latency < 300) return '#ffb300';
  82. return latency < 500 ? '#ff9800' : '#f44336';
  83. };
  84.  
  85. const measureLatency = () => {
  86. const controller = new AbortController();
  87. const timeoutId = setTimeout(() => controller.abort(), 5000);
  88. const start = performance.now();
  89. fetch(`${location.origin}/?t=${start}`, {
  90. method: 'HEAD',
  91. mode: 'no-cors',
  92. cache: 'no-store',
  93. signal: controller.signal
  94. }).then(() => {
  95. const latency = performance.now() - start;
  96. latencyPanel.textContent = `延迟: ${latency.toFixed(1)}ms`;
  97. latencyPanel.style.color = getLatencyColor(latency);
  98. }).catch(e => {
  99. latencyPanel.textContent = e.name === 'AbortError' ? '延迟: 超时' : '延迟: 断开';
  100. latencyPanel.style.color = '#f44336';
  101. }).finally(() => clearTimeout(timeoutId));
  102. };
  103.  
  104. const syncUpdate = () => {
  105. measureLatency();
  106. updateTimer = setTimeout(syncUpdate, 2000);
  107. };
  108.  
  109. const handleVisibilityChange = () => {
  110. clearTimeout(updateTimer);
  111. if (document.hidden) {
  112. resourceObserver?.disconnect();
  113. } else {
  114. initResourceObserver();
  115. syncUpdate();
  116. }
  117. };
  118.  
  119. window.addEventListener('scroll', () => {
  120. container.style.opacity = '0.7';
  121. clearTimeout(scrollTimer);
  122. scrollTimer = setTimeout(() => container.style.opacity = '1', 800);
  123. }, { passive: true });
  124.  
  125. document.addEventListener('visibilitychange', handleVisibilityChange);
  126. window.addEventListener('beforeunload', () => {
  127. resourceObserver?.disconnect();
  128. clearTimeout(updateTimer);
  129. clearTimeout(scrollTimer);
  130. });
  131.  
  132. initResourceObserver();
  133. syncUpdate();
  134. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址