Tampermonkey脚本刷新后持久化迭代计数实现指定运行逻辑求助
实现方案
你之前的代码存在四个核心问题:
- 同步for循环会瞬间触发两次
main()调用,和函数内部基于setTimeout的异步DOM重命名逻辑冲突,导致功能异常 - 未处理
main()内部自动跳转至正确子页面的场景,跳转动作的无效执行被计入运行次数 - 计数达到阈值后未做重置,页面刷新后会一直卡在计数满的状态,无法循环执行
- 缺少同页面运行锁,导致脚本重复触发,出现你提到的每秒重复运行问题
直接替换原脚本全部内容为以下版本即可实现需求:
// ==UserScript== // @name Shinko BT Renamer // @namespace http://tampermonkey.net/ // @version 0.2 // @description try to take over the world! // @author You // @match https://*/game.php*mode=incomings* // @icon https://www.google.com/s2/favicons?sz=64&domain=devilicious.dev // @grant GM_setValue // @grant GM_getValue // ==/UserScript== var FORMAT = "#unit# from #coords# -> BT: #backtime#"; let refreshTime = 5; // 页面刷新等待时间,单位分钟 // 全局运行锁,防止同页面重复初始化 if (window.__btRenamerInited) return; window.__btRenamerInited = true; function main() { if(window.location.href.indexOf("subtype=attacks")==-1) { window.location.href = window.location.pathname+ "?screen=overview_villages&mode=incomings&mode=incomings&subtype=attacks"; return; } if (typeof FORMAT === 'undefined') FORMAT = "#unit# from #coords# - #player# Backtime: #backtime#"; FORMAT = FORMAT.replace(/#/g, "%"); if(FORMAT.match(/%backtime%/g)!=null) FORMAT = ("`" + FORMAT + "`").replace(/%backtime%/, "%return%:${('00' + ((arrivalSeconds+parseInt('%duration%'.split(':')[2]))%60).toString()).slice(-2)}"); console.log(FORMAT); $('input[name=label_format]').val(FORMAT); let tagRows =$("#incomings_table > tbody > tr").not(':first').not(':last'); tagRows = $.grep(tagRows, (obj)=> $(".quickedit-label", obj)[0].innerText.match(/`.*`/g)!=null); if(tagRows.length >0) $.map(tagRows, (obj, key)=>setTimeout(()=>{ evalTag(obj); }, 250* key)); else tagCommands(); return tagRows.length; } function renameCommand(command, name) { $('.rename-icon', command).click(); $('.quickedit-edit input[type="text"]', command).val(name); $('.quickedit-edit input[type="button"]', command).click(); } function evalTag(row) { let command = $("td:nth-child(1)", row)[0]; let arrivalTime = $("td:nth-child(6)", row)[0].innerText; let arrivalSeconds = parseInt(arrivalTime.split(":")[2]); let evalCommandTag; try { evalCommandTag = eval(command.innerText); } catch(err) { evalCommandTag = command.innerText; } renameCommand(command, evalCommandTag); } function tagCommands() { if($("#incomings_form").length > 0) { selectAll($("#incomings_form")[0], true); $("[name='label']")[0].click(); } } // 执行流程控制 const COUNT_STORAGE_KEY = 'bt_renamer_run_count'; function runWorkflow() { let currentCount = GM_getValue(COUNT_STORAGE_KEY, 0); if (currentCount < 2) { const preRunUrl = window.location.href; // 执行主逻辑,返回待处理的行数量,用于计算异步操作等待时间 const rowCount = main(); // 未触发页面跳转才是有效执行 if (preRunUrl.includes("subtype=attacks")) { currentCount++; GM_setValue(COUNT_STORAGE_KEY, currentCount); // 等待所有异步重命名操作完成后,再触发下一轮执行 const waitMs = (rowCount || 0) * 250 + 500; setTimeout(runWorkflow, waitMs); } } else { // 两次执行完成,等待指定时间后刷新 setTimeout(() => { // 刷新前重置计数,下一轮页面加载从0开始 GM_setValue(COUNT_STORAGE_KEY, 0); window.location.reload(); }, refreshTime * 60 * 1000); } } // 页面加载完成后启动流程 window.addEventListener('load', runWorkflow);
关键逻辑说明
- 运行锁通过全局变量标记初始化状态,解决脚本每秒重复执行的问题
- 基于Tampermonkey的GM存储API持久化执行计数,页面刷新后状态不会丢失
- 自动识别
main()触发的页面跳转动作,这类未执行核心逻辑的跳转不会计入运行次数 - 主逻辑执行后会等待所有异步DOM重命名操作全部完成,再启动下一次执行,避免操作冲突
- 触发页面前置零存储的计数,保证刷新后的新一轮流程可以正常从0开始计数
内容的提问来源于stack exchange,提问作者jose alevs
相关产品推荐
相关产品推荐

