我正在开发一个 Tampermonkey/Greasemonkey 脚本,该脚本会在此页面上的表格中添加一个新列https://www.fangraphs.com/leaders/major-league.
我有一个工作版本,添加了该列,看起来像这样
我希望能够在网格刷新时重新运行脚本(例如,当单击其中一个表标题对数据进行排序时)。问题是,如果我添加代码来观察表何时发生变化,它会在我添加列时触发。我确实注意到,当页面发生更改时,会向 DOM 添加一个 div,其中包含一个名为“fgui-loading”的类。有没有办法在初始页面加载后为该 div 添加观察者?
这是我的工作脚本,它添加了列,但正如您所看到的,对列进行排序不会更新最后一个列。
(function () {
"use strict";
// Mock function to get the free agent year of a player
function getFreeAgentYear(playerName) {
// In a real scenario, this data would be fetched from an API or database
let freeAgentData =
{
"Aaron Judge" : "FREE AGENT 2029",
"Juan Soto" : "After 2030"
};
return freeAgentData[playerName] || "Not on Roster or After 2030";
}
// Function to add the "Free Agent Year" column
function addFreeAgentYearColumn() {
const table = document.querySelector(".table-scroll");
if (!table) return;
// Add the header for the new column
const headerRow = table.querySelector("thead tr");
if (headerRow) {
const newHeader = document.createElement("th");
newHeader.innerText = "Club Control";
headerRow.appendChild(newHeader);
}
// Add the free agent year data for each player
const rows = table.querySelectorAll("tbody tr");
rows.forEach((row) => {
const playerNameCell = row.querySelector("td a");
if (playerNameCell) {
const playerName = playerNameCell.innerText.trim();
const freeAgentYear = getFreeAgentYear(playerName);
const newCell = document.createElement("td");
newCell.innerText = freeAgentYear;
row.appendChild(newCell);
}
});
}
const initialObserver = new MutationObserver((mutations) => {
var processed = false;
mutations.forEach(() => {
if (document.querySelector(".table-scroll")) {
if (document.querySelector(".table-scroll")) {
const table = document.querySelector(".table-scroll");
if (
table.querySelectorAll("tbody tr").length > 1 &&
processed == false
) {
addFreeAgentYearColumn();
processed = true;
initialObserver.disconnect();
}
}
}
});
});
initialObserver.observe(document.body, { childList: true, subtree: true });
})();
感谢对此的帮助!
观察
.fgui-loading
并不能解决问题,因为该元素仅在从网络获取数据时出现,一旦数据被缓存,它就不会再出现。
都不会监听标题上的点击,因为您仍然需要确保加载/刷新完成并插入新值,以便您的函数不会使用以前的值。
最简单/最简单的方法是观察
tbody
元素并在更新时调用 addFreeAgentYearColumn
。
这可以方便地处理更改页码或页面大小,甚至更改选项卡。
注意:我只在大联盟页面及其选项卡上测试了此代码,您可能需要调整它才能在其他页面上工作。
function getFreeAgentYear(playerName) {
let freeAgentData =
{
"Aaron Judge" : "FREE AGENT 2029",
"Juan Soto" : "After 2030"
};
return freeAgentData[playerName] || "Not on Roster or After 2030";
}
function addFreeAgentYearColumn() {
const table = document.querySelector("div.table-scroll > table");
if (!table) return;
// disconnect observer to avoid infinite loop
observer.disconnect();
// remove old header/cells (from tables that don't have player names and avoid duplication)
table.querySelectorAll('#club-control').forEach( ele => ele.remove() );
// return if this table does not have a playerName header
const playerNameHeader = table.tHead.querySelector("th[data-col-id=Name]");
if (!playerNameHeader) return;
const clubControlHeader = document.createElement("th");
clubControlHeader.innerText = "Club Control";
clubControlHeader.id = "club-control";
table.tHead.rows[0].appendChild(clubControlHeader);
const rows = table.tBodies[0].rows;
for (let i=0; i < rows.length; ++i){
//const playerNameCell = rows[i].cells[1];
const playerNameCell = rows[i].querySelector("td[data-col-id=Name]");
if (!playerNameCell) return;
const playerName = playerNameCell.textContent;
const freeAgentYear = getFreeAgentYear(playerName);
const clubControlCell = document.createElement("td");
clubControlCell.id = "club-control";
clubControlCell.innerText = freeAgentYear;
rows[i].appendChild(clubControlCell);
};
// reconnect the observer
const target = table.tBodies[0];
const config = {childList: true, subtree: true};
observer.observe(target, config);
}
const observer = new MutationObserver(addFreeAgentYearColumn);
addFreeAgentYearColumn();