对于使用 Typecho Handsome 主题的博主来说,在侧边栏添加一个能实时反馈网站负载的 QPS (每秒查询率) 图表,是一项非常酷的功能。然而,Handsome 主题强大的 PJAX 无刷新加载特性,也给这类需要持续运行的动态脚本带来了挑战。 本教程将详细介绍如何创建一个与 PJAX 完全兼容的实时 QPS 图表,彻底解决在页面跳转后图表“罢工”、数据不再更新的问题。 ## 一、最终效果 我们最终实现的效果是,在博客侧边栏有一个动态的QPS图表,无论您是首次加载页面,还是通过PJAX在不同页面间导航,这个图表都能持续、稳定地从服务器获取最新数据并实时渲染。 ## 二、实现原理 为了完美兼容PJAX,我们将整个功能拆分为三个核心部分,各司其职: 1. **后台数据更新器**:这是“数据源”的核心。它由一个JavaScript脚本 (`qps-updater.js`) 和一个PHP脚本 (`update-qps.php`) 组成。`qps-updater.js` 会在后台持续运行,每隔5秒就向 `update-qps.php` 发起请求,后者则负责从您的WAF(如长亭雷池)获取最新的QPS数据,并将其写入一个简单的服务器缓存文件 (`safeguard_qps.json`)。 2. **前台图表渲染器**:这是“看得见”的部分。它位于您的侧边栏 (`sidebar.php`),包含一个图表容器 (``) 和一段独立的 ECharts 渲染脚本。这段脚本只做一件事:同样每隔5秒,从另一个PHP脚本 (`get-qps.php`) 读取上述的缓存文件,然后将数据绘制成图表。 3. **PJAX 兼容粘合剂**:这是解决问题的关键。我们将前台图表的初始化逻辑,封装在一个全局函数 `initQPSChartForHandsome()` 中。然后,我们只需在 Handsome 主题后台的PJAX回调设置中填入这个函数名。这样,每次PJAX导航完成,主题就会自动调用这个函数,它会先**彻底清理**掉旧的图表实例和定时器,再**重新初始化**一个新的,从而实现了完美的无缝衔接。 这种前后端分离、逻辑解耦的架构,确保了即使在复杂的PJAX环境中,数据更新和图表渲染也能独立、稳定地运行。 ## 三、文件准备 请将以下4个文件,按照指定的路径和内容,放置到您的主题目录中。 > **注意**:本教程假设您已在 `/usr/themes/handsome/static/js/` 目录下放置了 `echarts.min.js` 文件。这是本地的ECharts图表库,您可以从 [ECharts官网](https://echarts.apache.org/zh/download.html) 下载最新版本。若您没有此文件,我们的加载器会自动尝试从CDN获取,但建议使用本地版本以获得更好的加载速度和稳定性。 #### 1. 数据读取脚本 **路径**: `/usr/themes/handsome/component/get-qps.php` *(该脚本用于让前台图表安全地读取缓存数据)* ```php 0, 'timestamp' => time(), 'simulated' => true]); } ``` #### 2. 数据更新脚本 **路径**: `/usr/themes/handsome/component/update-qps.php` *(该脚本用于从WAF获取真实数据并写入缓存)* [hide] ```php $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, // 生产环境建议设为true并配置证书 CURLOPT_SSL_VERIFYHOST => false, CURLOPT_HTTPHEADER => ['Accept: application/json', 'X-SLCE-API-TOKEN: ' . $token], CURLOPT_TIMEOUT => 5, ]); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($http_code !== 200 || !$response) return null; $data = json_decode($response, true); if (!isset($data['data']['nodes']) || empty($data['data']['nodes'])) return null; $latestNode = end($data['data']['nodes']); foreach ($latestNode as $key => $value) { if ($key !== 'time' && is_numeric($value)) return floatval($value); } return null; } $qps = fetch_qps_from_api($api_url, $api_token); $output_data = [ 'qps' => ($qps !== null) ? $qps : 0, // 如果API失败,则返回0 'timestamp' => time(), 'simulated' => ($qps === null) ]; file_put_contents($cache_file, json_encode($output_data)); header('Content-Type: application/json'); echo json_encode(['success' => true, 'data' => $output_data]); ``` [/hide] ![][1] #### 3. ECharts 延迟加载器 **路径**: `/usr/themes/handsome/static/js/echarts-loader.js` *(这是我们修改过的、兼容PJAX的版本)* ```javascript /** * ECharts 延迟加载器 (PJAX兼容版) * 只在需要时才加载 ECharts 库,避免阻塞页面渲染 */ (function() { function safeLog(message, type) { try { if (window.console && typeof window.console[type || 'log'] === 'function') { window.console[type || 'log'](message); } } catch (e) {} } window.ECHARTS_LOADER = { loaded: false, loading: false, callbacks: [], localPath: '/usr/themes/handsome/static/js/echarts.min.js', // 本地ECharts库路径 cdnPath: 'https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js', onLoad: function(callback) { if (typeof callback !== 'function') return; if (this.loaded && window.echarts) { callback(window.echarts); } else { this.callbacks.push(callback); if (!this.loading) this.loadECharts(); } }, loadECharts: function() { if (this.loading || this.loaded) return; this.loading = true; var self = this; var script = document.createElement('script'); script.type = 'text/javascript'; script.src = this.localPath; // 优先使用本地路径 script.onload = function() { self.loaded = true; self.loading = false; safeLog('ECharts 加载成功', 'info'); while (self.callbacks.length > 0) { try { self.callbacks.shift()(window.echarts); } catch (e) {} } }; // 仅在本地加载失败时,才尝试从CDN加载 script.onerror = function() { safeLog('从本地加载 ECharts 失败,尝试从 CDN 加载', 'warn'); script.src = self.cdnPath; script.onerror = function() { safeLog('从 CDN 加载 ECharts 也失败了', 'error'); self.loading = false; self.callbacks = []; }; }; document.body.appendChild(script); } }; function checkForEChartsElements() { if (window.echarts) { window.ECHARTS_LOADER.loaded = true; return; } var chartContainers = document.querySelectorAll('.top-echart, #safeguard-qps-chart, #steps-chart, #sleep-chart'); if (chartContainers.length > 0) { window.ECHARTS_LOADER.loadECharts(); } } if (document.readyState === 'complete') { checkForEChartsElements(); } else { window.addEventListener('load', checkForEChartsElements); } // PJAX 兼容处理 document.addEventListener('pjax:end', checkForEChartsElements); window.loadECharts = function(callback) { window.ECHARTS_LOADER.onLoad(callback); }; })(); ``` #### 4. 后台数据更新器 (JS) **路径**: `/usr/themes/handsome/component/qps-updater.js` *(这是我们修改过的、兼容PJAX的版本)* [hide] ```javascript /** * 雷池WAF QPS数据后台自动更新脚本 - PJAX兼容版 */ // 使用全局卫兵变量,确保脚本只初始化一次 if (typeof window.qpsUpdaterIntervalId === 'undefined') { window.qpsUpdaterIntervalId = null; } (function () { if (window.qpsUpdaterIntervalId !== null) { if (window.console) console.log('[QPS后台更新器] 更新器已在运行,本次初始化跳过。'); return; } const config = { updateInterval: 5000, updateEndpoint: '/usr/themes/handsome/component/update-qps.php', debugMode: true // 建议在排错时开启,正常运行时可设为false }; function safeLog(message, type = 'log') { if (config.debugMode && window.console && typeof window.console[type] === 'function') { window.console[type]('[QPS后台更新器] ' + message); } } function updateQPSData() { safeLog('正在向服务器请求更新QPS数据...'); fetch(config.updateEndpoint, { method: 'GET', headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(response => { if (!response.ok) throw new Error('网络错误: ' + response.status); return response.json(); }) .then(data => { if (data.success) safeLog('服务器成功更新QPS数据。'); else safeLog('服务器更新QPS数据失败: ' + (data.error || '未知错误'), 'warn'); }) .catch(error => safeLog('请求更新QPS数据时出错: ' + error.message, 'error')); } function init() { safeLog('初始化...'); updateQPSData(); window.qpsUpdaterIntervalId = setInterval(updateQPSData, config.updateInterval); safeLog('已启动,更新间隔: ' + config.updateInterval + 'ms'); } init(); })(); ``` [/hide] ## 四、侧边栏集成 现在,编辑您的侧边栏文件(例如 `usr/themes/handsome/component/sidebar.php` 或主题本身的 `sidebar.php`),在您希望显示图表的位置,加入以下代码块。 ```php 实时QPS 0 ``` ## 五、整合与配置 (关键步骤) 1. **确认文件位置**:确保您已经将第三、四部分的所有文件都正确地放置到了您的主题目录下。 - 数据操作相关脚本:`/usr/themes/handsome/component/` 目录下的 `get-qps.php` 和 `update-qps.php` - ECharts 加载器和库文件:`/usr/themes/handsome/static/js/` 目录下的 `echarts-loader.js` 和 `echarts.min.js` - 后台更新脚本:`/usr/themes/handsome/component/` 目录下的 `qps-updater.js` 2. **准备ECharts库**:如果您还没有,请从[ECharts官网](https://echarts.apache.org/zh/download.html)下载最新版本的`echarts.min.js`文件,并将其放置于`/usr/themes/handsome/static/js/`目录下,与加载器脚本位于同一目录。这是本地图表库文件,可提供更好的加载性能。 3. **创建缓存目录**:手动在 `/usr/themes/handsome/component/` 目录下创建一个名为 `cache` 的文件夹,并确保PHP对它有写入权限(权限 `755` 或 `777`)。 4. **引入核心加载器**:编辑主题的 `header.php` 或 `footer.php` 文件,确保 `echarts-loader.js` 被引入。您只需添加一行: `` 5. **配置 Handsome 主题 PJAX 回调**: * 进入您的 **Handsome 主题后台**。 * 找到 **PJAX相关设置**(通常在"全局设置"或"速度优化"等菜单下)。 * 检查"**PJAX回调函数**"输入框中的内容: - **如果输入框为空**:直接填入 `initQPSChartForHandsome` - **如果已有其他函数**:您需要采用以下方式整合多个函数(请勿直接覆盖现有内容): ```javascript // 保留您现有的所有函数代码... // 在最后添加QPS图表初始化 if (typeof initQPSChartForHandsome === 'function') { initQPSChartForHandsome(); } ``` * 保存设置。 ## 六、故障排查 如果配置后图表未显示或数据不更新,请按以下步骤检查: 1. **清除浏览器缓存**,强制加载最新的JS文件。 2. **检查缓存目录权限**:确认 `/usr/themes/handsome/component/cache` 目录存在且可写。 3. **打开浏览器开发者工具 (F12)**: * 切换到 **“控制台 (Console)”** 选项卡,查看是否有红色的错误信息。我们开启了调试模式,您应该能看到 `[QPS后台更新器]` 开头的日志,这表示后台更新脚本正在工作。 * 切换到 **“网络 (Network)”** 选项卡,筛选 `Fetch/XHR`,检查是否每5秒都有对 `update-qps.php` 和 `get-qps.php` 的网络请求,以及它们的返回状态是否为 `200`。 通过以上步骤,您就能在博客中拥有一个稳定、可靠、且与 Handsome 主题完美兼容的实时QPS监控图表了。 [1]: https://static.blog.ybyq.wang/usr/uploads/2025/07/25/2025-07-25T02:57:47.png?x-oss-process=style/shuiyin AI摘要 本文介绍了如何在Typecho Handsome主题中添加实时QPS图表,使其与PJAX功能兼容。通过三个核心部分:后台数据更新器、前台图表渲染器和PJAX兼容粘合剂,实现了在侧边栏显示实时QPS图表的功能。文章提供了详细的实现原理、文件准备、侧边栏集成和整合配置步骤,并提供了故障排查方法。 此内容根据文章生成,仅用于文章内容的解释与总结 对于使用 Typecho Handsome 主题的博主来说,在侧边栏添加一个能实时反馈网站负载的 QPS (每秒查询率) 图表,是一项非常酷的功能。然而,Handsome 主题强大的 PJAX 无刷新加载特性,也给这类需要持续运行的动态脚本带来了挑战。本教程将详细介绍如何创建一个与 PJAX 完全兼容的实时 QPS 图表,彻底解决在页面跳转后图表“罢工”、数据不再更新的问题。一、最终效果我们最终实现的效果是,在博客侧边栏有一个动态的QPS图表,无论您是首次加载页面,还是通过PJAX在不同页面间导航,这个图表都能持续、稳定地从服务器获取最新数据并实时渲染。二、实现原理为了完美兼容PJAX,我们将整个功能拆分为三个核心部分,各司其职:后台数据更新器:这是“数据源”的核心。它由一个JavaScript脚本 (qps-updater.js) 和一个PHP脚本 (update-qps.php) 组成。qps-updater.js 会在后台持续运行,每隔5秒就向 update-qps.php 发起请求,后者则负责从您的WAF(如长亭雷池)获取最新的QPS数据,并将其写入一个简单的服务器缓存文件 (safeguard_qps.json)。前台图表渲染器:这是“看得见”的部分。它位于您的侧边栏 (sidebar.php),包含一个图表容器 (<div>) 和一段独立的 ECharts 渲染脚本。这段脚本只做一件事:同样每隔5秒,从另一个PHP脚本 (get-qps.php) 读取上述的缓存文件,然后将数据绘制成图表。PJAX 兼容粘合剂:这是解决问题的关键。我们将前台图表的初始化逻辑,封装在一个全局函数 initQPSChartForHandsome() 中。然后,我们只需在 Handsome 主题后台的PJAX回调设置中填入这个函数名。这样,每次PJAX导航完成,主题就会自动调用这个函数,它会先彻底清理掉旧的图表实例和定时器,再重新初始化一个新的,从而实现了完美的无缝衔接。这种前后端分离、逻辑解耦的架构,确保了即使在复杂的PJAX环境中,数据更新和图表渲染也能独立、稳定地运行。三、文件准备请将以下4个文件,按照指定的路径和内容,放置到您的主题目录中。注意:本教程假设您已在 /usr/themes/handsome/static/js/ 目录下放置了 echarts.min.js 文件。这是本地的ECharts图表库,您可以从 ECharts官网 下载最新版本。若您没有此文件,我们的加载器会自动尝试从CDN获取,但建议使用本地版本以获得更好的加载速度和稳定性。1. 数据读取脚本路径: /usr/themes/handsome/component/get-qps.php(该脚本用于让前台图表安全地读取缓存数据)<?php // usr/themes/handsome/component/get-qps.php header('Content-Type: application/json; charset=utf-8'); header('Cache-Control: no-cache, no-store, must-revalidate'); $cache_dir = __DIR__ . '/cache'; $cache_file = $cache_dir . '/safeguard_qps.json'; if (file_exists($cache_file)) { echo file_get_contents($cache_file); } else { // 如果缓存文件不存在,返回一个默认的JSON结构 echo json_encode(['qps' => 0, 'timestamp' => time(), 'simulated' => true]); }2. 数据更新脚本路径: /usr/themes/handsome/component/update-qps.php(该脚本用于从WAF获取真实数据并写入缓存)此处内容需要评论回复后(审核通过)方可阅读。3. ECharts 延迟加载器路径: /usr/themes/handsome/static/js/echarts-loader.js(这是我们修改过的、兼容PJAX的版本)/** * ECharts 延迟加载器 (PJAX兼容版) * 只在需要时才加载 ECharts 库,避免阻塞页面渲染 */ (function() { function safeLog(message, type) { try { if (window.console && typeof window.console[type || 'log'] === 'function') { window.console[type || 'log'](message); } } catch (e) {} } window.ECHARTS_LOADER = { loaded: false, loading: false, callbacks: [], localPath: '/usr/themes/handsome/static/js/echarts.min.js', // 本地ECharts库路径 cdnPath: 'https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js', onLoad: function(callback) { if (typeof callback !== 'function') return; if (this.loaded && window.echarts) { callback(window.echarts); } else { this.callbacks.push(callback); if (!this.loading) this.loadECharts(); } }, loadECharts: function() { if (this.loading || this.loaded) return; this.loading = true; var self = this; var script = document.createElement('script'); script.type = 'text/javascript'; script.src = this.localPath; // 优先使用本地路径 script.onload = function() { self.loaded = true; self.loading = false; safeLog('ECharts 加载成功', 'info'); while (self.callbacks.length > 0) { try { self.callbacks.shift()(window.echarts); } catch (e) {} } }; // 仅在本地加载失败时,才尝试从CDN加载 script.onerror = function() { safeLog('从本地加载 ECharts 失败,尝试从 CDN 加载', 'warn'); script.src = self.cdnPath; script.onerror = function() { safeLog('从 CDN 加载 ECharts 也失败了', 'error'); self.loading = false; self.callbacks = []; }; }; document.body.appendChild(script); } }; function checkForEChartsElements() { if (window.echarts) { window.ECHARTS_LOADER.loaded = true; return; } var chartContainers = document.querySelectorAll('.top-echart, #safeguard-qps-chart, #steps-chart, #sleep-chart'); if (chartContainers.length > 0) { window.ECHARTS_LOADER.loadECharts(); } } if (document.readyState === 'complete') { checkForEChartsElements(); } else { window.addEventListener('load', checkForEChartsElements); } // PJAX 兼容处理 document.addEventListener('pjax:end', checkForEChartsElements); window.loadECharts = function(callback) { window.ECHARTS_LOADER.onLoad(callback); }; })();4. 后台数据更新器 (JS)路径: /usr/themes/handsome/component/qps-updater.js(这是我们修改过的、兼容PJAX的版本)此处内容需要评论回复后(审核通过)方可阅读。四、侧边栏集成现在,编辑您的侧边栏文件(例如 usr/themes/handsome/component/sidebar.php 或主题本身的 sidebar.php),在您希望显示图表的位置,加入以下代码块。<!-- 雷池WAF实时QPS图表 --> <section id="safeguard_qps_chart_widget" class="widget widget_categories wrapper-md padder-v-none clear"> <h5 class="widget-title m-t-none">实时QPS</h5> <div class="panel wrapper-sm padder-v-ssm"> <div class="safeguard-qps-chart-container" style="position:relative; height:180px; padding:15px; border-radius:8px; box-shadow:0 2px 5px rgba(0,0,0,0.05);"> <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:10px;"> <span style="font-size:16px; font-weight:bold; color:#333;"> <i data-feather="activity" style="width:16px; height:16px; vertical-align:middle; margin-right:4px; color:#20c997;"></i> <span id="current-qps">0</span> </span> <span id="refresh-btn" style="cursor:pointer; color:#20c997;"> <i data-feather="refresh-cw" style="width:14px; height:14px;"></i> </span> </div> <div id="safeguard-qps-chart" style="width:100%; height:120px;"></div> </div> <script> (function() { // 使用闭包管理状态,避免全局污染 let qpsChart = null; let intervalId = null; let qpsData = []; let timeLabels = []; const maxDataPoints = 15; function cleanup() { if (intervalId) clearInterval(intervalId); if (qpsChart) { try { qpsChart.dispose(); } catch (e) {} } qpsChart = null; intervalId = null; qpsData = []; timeLabels = []; const chartElement = document.getElementById('safeguard-qps-chart'); if (chartElement) chartElement.removeAttribute('data-qps-init'); } // 将初始化函数暴露到全局,以便Handsome主题回调 window.initQPSChartForHandsome = function() { cleanup(); const chartElement = document.getElementById('safeguard-qps-chart'); if (!chartElement) return; function fetchQPSData() { fetch('/usr/themes/handsome/component/get-qps.php?t=' + Date.now()) .then(res => res.json()) .then(data => { if (!data) return; const qpsVal = parseFloat(data.qps || 0); const now = new Date(); const timeStr = now.getHours() + ':' + ('0' + now.getMinutes()).slice(-2) + ':' + ('0' + now.getSeconds()).slice(-2); const currentQpsEl = document.getElementById('current-qps'); if (currentQpsEl) currentQpsEl.textContent = qpsVal.toFixed(2); qpsData.push(qpsVal); timeLabels.push(timeStr); if (qpsData.length > maxDataPoints) { qpsData.shift(); timeLabels.shift(); } drawChart(); }).catch(console.error); } function drawChart() { if (!window.loadECharts) return; window.loadECharts(function(echarts) { try { if (!qpsChart) { qpsChart = echarts.init(chartElement); window.addEventListener('resize', () => qpsChart && qpsChart.resize()); } qpsChart.setOption({ tooltip: { trigger: 'axis', formatter: p => `${timeLabels[p[0].dataIndex]}<br/>QPS: <strong>${p[0].value}</strong>` }, grid: { left: '3%', right: '10%', bottom: '10%', top: '10%', containLabel: true }, xAxis: { type: 'category', data: timeLabels, show: false }, yAxis: { type: 'value', splitLine: { lineStyle: { type: 'dashed' } } }, series: [{ data: qpsData, type: 'line', smooth: true, showSymbol: false, lineStyle: { color: '#20c997' }, areaStyle: { color: '#20c997', opacity: 0.1 } }] }); } catch (e) { console.error("ECharts渲染失败:", e); } }); } // 动态加载后台更新器脚本 if (typeof window.qpsUpdaterLoaded === 'undefined') { const updaterScript = document.createElement('script'); updaterScript.src = '/usr/themes/handsome/component/qps-updater.js?v=' + Date.now(); document.body.appendChild(updaterScript); window.qpsUpdaterLoaded = true; } fetchQPSData(); intervalId = setInterval(fetchQPSData, 5000); const refreshBtn = document.getElementById('refresh-btn'); if (refreshBtn) { const newBtn = refreshBtn.cloneNode(true); refreshBtn.parentNode.replaceChild(newBtn, refreshBtn); newBtn.addEventListener('click', fetchQPSData); } }; // 首次加载时自动运行 document.addEventListener('DOMContentLoaded', window.initQPSChartForHandsome); })(); </script> </div> </section>五、整合与配置 (关键步骤)确认文件位置:确保您已经将第三、四部分的所有文件都正确地放置到了您的主题目录下。数据操作相关脚本:/usr/themes/handsome/component/ 目录下的 get-qps.php 和 update-qps.phpECharts 加载器和库文件:/usr/themes/handsome/static/js/ 目录下的 echarts-loader.js 和 echarts.min.js后台更新脚本:/usr/themes/handsome/component/ 目录下的 qps-updater.js准备ECharts库:如果您还没有,请从ECharts官网下载最新版本的echarts.min.js文件,并将其放置于/usr/themes/handsome/static/js/目录下,与加载器脚本位于同一目录。这是本地图表库文件,可提供更好的加载性能。创建缓存目录:手动在 /usr/themes/handsome/component/ 目录下创建一个名为 cache 的文件夹,并确保PHP对它有写入权限(权限 755 或 777)。引入核心加载器:编辑主题的 header.php 或 footer.php 文件,确保 echarts-loader.js 被引入。您只需添加一行:<script src="<?php $this->options->themeUrl('static/js/echarts-loader.js'); ?>"></script>配置 Handsome 主题 PJAX 回调:进入您的 Handsome 主题后台。找到 PJAX相关设置(通常在"全局设置"或"速度优化"等菜单下)。检查"PJAX回调函数"输入框中的内容:如果输入框为空:直接填入 initQPSChartForHandsome如果已有其他函数:您需要采用以下方式整合多个函数(请勿直接覆盖现有内容):// 保留您现有的所有函数代码... // 在最后添加QPS图表初始化 if (typeof initQPSChartForHandsome === 'function') { initQPSChartForHandsome(); }保存设置。六、故障排查如果配置后图表未显示或数据不更新,请按以下步骤检查:清除浏览器缓存,强制加载最新的JS文件。检查缓存目录权限:确认 /usr/themes/handsome/component/cache 目录存在且可写。打开浏览器开发者工具 (F12):切换到 “控制台 (Console)” 选项卡,查看是否有红色的错误信息。我们开启了调试模式,您应该能看到 [QPS后台更新器] 开头的日志,这表示后台更新脚本正在工作。切换到 “网络 (Network)” 选项卡,筛选 Fetch/XHR,检查是否每5秒都有对 update-qps.php 和 get-qps.php 的网络请求,以及它们的返回状态是否为 200。通过以上步骤,您就能在博客中拥有一个稳定、可靠、且与 Handsome 主题完美兼容的实时QPS监控图表了。 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏 END 本文作者: xuan 文章标题:Typecho Handsome 添加实时QPS图表 - 兼容pjax 本文地址:https://blog.ybyq.wang/archives/776.html 版权说明:若无注明,本文皆Xuan's blog原创,转载请保留文章出处。 文章引用 反向引用 Loading... 暂未引用其他文章 暂未被其它文章引用 下一篇 上一篇 ※最新文章推荐※ Typecho handsome侧边栏显示网站请求总数 2025-07-25 Typecho Handsome 添加实时QPS图表 - 兼容pjax 2025-07-25 PHP插件开发中的一个错误:JSON直接输出导致网站首页异常 2025-07-22 Cursor中国区服务限制分析及应对方案 2025-07-18 Typecho博客Handsome主题侧边栏添加QQ等级和信息显示功能教程 2025-07-17 分享60个有趣实用的API及其Typecho博客集成指南 2025-07-17 发表评论 取消回复 使用cookie技术保留您的个人信息以便您下次快速评论,继续评论表示您已同意该条款 评论 * 打卡 语录 私密评论 名称 * 🎲 邮箱 * 地址 发表评论 提交中...