如何让Userscript在同URL后续页面导航中重复执行所有操作?
解决单页应用下Userscript重复执行及元素容错问题
一、元素不存在的容错处理
要避免因目标元素不存在导致脚本中断,直接跳过该操作执行后续逻辑,可采用两种写法:
简洁写法(ES2020+,油猴脚本默认支持)
利用可选链操作符?.,元素不存在时不会抛出错误,直接跳过:
document.querySelector('[title="Select: This option"]')?.checked = true document.querySelector('[title="Click to continue"]')?.click()
兼容旧环境写法
通过判断元素是否存在再执行操作:
const selectOption = document.querySelector('[title="Select: This option"]') if (selectOption) { selectOption.checked = true } const continueBtn = document.querySelector('[title="Click to continue"]') if (continueBtn) { continueBtn.click() }
二、优雅监听单页应用内容更新(替代定时器)
因为页面是URL不变的跳转(单页应用SPA),DOM会动态更新,传统脚本初始化逻辑只会执行一次。用MutationObserver监听DOM变化是更高效精准的方案,比定时器性能更好。
完整实现代码
// 封装核心操作,方便重复调用 function executeActions() { // 容错处理:元素不存在则跳过 document.querySelector('[title="Select: This option"]')?.checked = true const continueBtn = document.querySelector('[title="Click to continue"]') if (continueBtn) { continueBtn.click() } } // 页面初始加载时先执行一次 executeActions() // 创建DOM变化观察者 const domObserver = new MutationObserver((mutations) => { // 检测是否有新内容添加或目标元素相关变化 const shouldRun = mutations.some(mutation => { // 存在新增节点,或目标按钮文本出现时触发 return mutation.addedNodes.length > 0 || mutation.target.textContent.includes("Click to continue") }) if (shouldRun) { executeActions() } }) // 配置监听范围:监听body下所有子元素及属性变化 domObserver.observe(document.body, { childList: true, subtree: true, attributes: true })
优化建议
- 缩小监听范围:如果知道内容更新的具体容器(比如某个带ID的div),替换
document.body为该容器,减少不必要的监听开销:
const targetContainer = document.getElementById('page-content') if (targetContainer) { domObserver.observe(targetContainer, { childList: true, subtree: true, attributes: true }) }
- 增加防抖:避免DOM频繁变化时重复执行脚本,给执行逻辑加防抖:
let debounceTimer = null function debouncedExecute() { clearTimeout(debounceTimer) debounceTimer = setTimeout(executeActions, 200) // 200ms延迟,可按需调整 } // 在MutationObserver回调中调用debouncedExecute()即可
内容的提问来源于stack exchange,提问作者f f
相关产品推荐
相关产品推荐

