Tampermonkey脚本:文档加载与分页点击时函数无法执行问题排查
解决Tampermonkey脚本触发时机与动态内容处理问题
问题背景
我正在编写Tampermonkey脚本扩展日常使用的业务Web应用,需求为提取页面中特定URL内的数字,并用该数字构建新链接追加到对应父元素中。
当前脚本存在以下问题:
- 文档加载完成时触发函数无效
- 点击类名为
pagination-sm的UL分页元素时触发函数无效 - 仅点击文档任意位置时函数可正常运行
推测原因:
- 页面实际数据加载滞后于JS文档加载事件触发时机
- 分页切换时动态生成新链接,原有绑定逻辑无法触发函数重新处理新内容
当前脚本代码
(function() { 'use strict'; //get the pagination element var element = document.getElementsByClassName('pagination-sm'); element.onclick = createLinks; document.onload = createLinks; function createLinks() { var links = document.querySelectorAll ("a[href*='/Field/POPendingCreate/']"); for (var J = links.length-1; J >= 0; --J) { var thisLink = links[J]; console.log(thisLink.href); var ppon = thisLink.href.match(/\d+/)[0]; console.log(ppon); var a = document.createElement('a'); var linkText = document.createTextNode("Preview Order"); a.appendChild(linkText); a.title = "Preview Order"; a.href = "https://website.com/Field/DownloadPendingPO?POPPKeyID=" + ppon + "&co=1&po=" + ppon; a.target = "_blank"; var parentNode = thisLink.parentNode; console.log(parentNode); parentNode.appendChild(a); } } })();
分页元素结构
<ul uib-pagination="" items-per-page="formData.itemPerPage" class="pagination-sm ng-pristine ng-untouched ng-valid ng-scope ng-isolate-scope pagination ng-not-empty" data-total-items="pendingList.length" data-ng-model="formData.currentPage" data-max-size="10" data-ng-if="!attachmentView && filteredDocuments.length > 0" role="menu"> <!-- ngIf: ::boundaryLinks --> <!-- ngIf: ::directionLinks --> <li role="menuitem" ng-if="::directionLinks" ng-class="{disabled: noPrevious()||ngDisabled}" class="pagination-prev ng-scope disabled"> <a href="" ng-click="selectPage(page - 1, $event)" ng-disabled="noPrevious()||ngDisabled" uib-tabindex-toggle="" class="ng-binding" disabled="disabled" tabindex="-1">Previous</a> </li> <!-- end ngIf: ::directionLinks --> <!-- ngRepeat: page in pages track by $index --> <li role="menuitem" ng-repeat="page in pages track by $index" ng-class="{active: page.active,disabled: ngDisabled&&!page.active}" class="pagination-page ng-scope active"> <a href="" ng-click="selectPage(page.number, $event)" ng-disabled="ngDisabled&&!page.active" uib-tabindex-toggle="" class="ng-binding">1</a> </li> <!-- end ngRepeat: page in pages track by $index --> <!-- ngIf: ::directionLinks --> <li role="menuitem" ng-if="::directionLinks" ng-class="{disabled: noNext()||ngDisabled}" class="pagination-next ng-scope disabled"> <a href="" ng-click="selectPage(page + 1, $event)" ng-disabled="noNext()||ngDisabled" uib-tabindex-toggle="" class="ng-binding" disabled="disabled" tabindex="-1">Next</a> </li> <!-- end ngIf: ::directionLinks --> <!-- ngIf: ::boundaryLinks --> </ul>
解决方案与修正脚本
核心问题分析
- 元素绑定错误:
getElementsByClassName返回HTMLCollection类数组,直接赋值onclick无效,需定位到具体元素。 - 加载事件错误:
document.onload不是标准加载事件,且无法覆盖异步加载的动态内容。 - 动态内容未监听:分页切换由Angular生成DOM,直接绑定点击事件会因元素动态更新失效,需用事件委托或MutationObserver监听内容变化。
修正后的脚本
(function() { 'use strict'; // 初始化:页面加载后先执行一次 window.addEventListener('load', init); function init() { createLinks(); setupEventDelegation(); setupMutationObserver(); } // 事件委托:监听分页点击(兼容Angular动态生成的元素) function setupEventDelegation() { document.addEventListener('click', function(e) { // 判断点击目标是否属于分页元素 if (e.target.closest('.pagination-sm')) { // 延迟执行,等待Angular更新DOM setTimeout(createLinks, 300); } }); } // MutationObserver:监听动态加载的链接元素 function setupMutationObserver() { // 替换为包含目标链接的父容器选择器(比如列表容器,找不到就用body) const targetNode = document.querySelector('body'); if (!targetNode) return; const config = { childList: true, subtree: true }; const observer = new MutationObserver(function(mutations) { // 检查是否有目标链接被添加 if (document.querySelector("a[href*='/Field/POPendingCreate/']")) { createLinks(); } }); observer.observe(targetNode, config); } function createLinks() { const links = document.querySelectorAll("a[href*='/Field/POPendingCreate/']"); links.forEach(link => { const parentNode = link.parentNode; // 避免重复添加链接 if (parentNode.querySelector('.preview-order-link')) return; const pponMatch = link.href.match(/\d+/); if (!pponMatch) return; const ppon = pponMatch[0]; const previewLink = document.createElement('a'); previewLink.className = 'preview-order-link'; // 标记已处理 previewLink.textContent = "Preview Order"; previewLink.title = "Preview Order"; previewLink.href = `https://website.com/Field/DownloadPendingPO?POPPKeyID=${ppon}&co=1&po=${ppon}`; previewLink.target = "_blank"; // 可添加样式区分 previewLink.style.marginLeft = '8px'; parentNode.appendChild(previewLink); }); } })();
关键改进点
- 事件委托:通过监听document的点击事件,判断点击源是否属于分页元素,避免直接绑定动态生成元素的点击事件失效。
- MutationObserver:监听DOM树变化,当动态加载的目标链接出现时自动执行处理逻辑,覆盖异步加载场景。
- 去重处理:给生成的预览链接添加类名标记,避免多次执行函数时重复创建链接。
- 延迟执行:分页点击后延迟300ms执行,确保Angular完成DOM更新后再处理新内容。
内容的提问来源于stack exchange,提问作者double07
相关产品推荐
相关产品推荐

