您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在 LeetCode 学习计划页面为每个分类显示题目总数,并为每个题目添加序号。
当前为
// ==UserScript== // @name LeetCode 学习计划题目序号 // @namespace http://tampermonkey.net/ // @version 0.2 // @description 在 LeetCode 学习计划页面为每个分类显示题目总数,并为每个题目添加序号。 // @author tianyw0 // @match https://leetcode.cn/studyplan/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; // 监听页面变化,确保在内容加载后执行脚本 const observer = new MutationObserver((mutationsList, observer) => { // 查找页面上所有符合“主容器”特征的模块 // 假设每个这样的模块都由一个 '.w-full.overflow-hidden.rounded-lg.border-\\[1\\.5px\\]' 类标识 const allProblemModules = document.querySelectorAll('.w-full.overflow-hidden.rounded-lg.border-\\[1\\.5px\\]'); // 只有当找到模块且至少有一个模块尚未处理时才执行 if (allProblemModules.length > 0 && !allProblemModules[0].dataset.processed) { allProblemModules.forEach(module => { // 防止重复处理 if (module.dataset.processed) { return; } const categoryTitles = module.querySelectorAll('div.flex.h-10 > div.text-\\[12px\\]'); const problemItemsInModule = module.querySelectorAll('div.flex.flex-col.border-b-\\[1\\.5px\\] > div.flex.h-\\[52px\\]'); const problemCount = problemItemsInModule.length; // 1. 在每个分类标题的文字后显示该模块的题目个数 categoryTitles.forEach(categoryTitleTextDiv => { // 检查是否已经添加过计数,避免重复 if (!categoryTitleTextDiv.querySelector('.problem-count-span')) { const countSpan = document.createElement('span'); countSpan.textContent = ` (${problemCount} 题)`; countSpan.style.marginLeft = '5px'; countSpan.classList.add('problem-count-span'); // 添加一个类以便识别 categoryTitleTextDiv.appendChild(countSpan); } }); // 2. 在当前模块内的具体题目前显示序号 problemItemsInModule.forEach((item, index) => { const titleContainer = item.querySelector('div.relative.flex.h-full.w-full.items-center > div.flex.w-0.flex-1.items-center.space-x-2'); if (titleContainer && !titleContainer.querySelector('.problem-index-span')) { // 检查是否已添加序号 const indexSpan = document.createElement('span'); indexSpan.textContent = `${index + 1}. `; indexSpan.classList.add('problem-index-span'); // 添加一个类以便识别 titleContainer.prepend(indexSpan); } }); // 标记此模块为已处理 module.dataset.processed = 'true'; }); // 首次成功处理后,可以停止观察,如果页面后续还有动态加载,则需要更精细的控制 // observer.disconnect(); } }); // 开始观察 body 元素下的 DOM 变化,特别是子节点的变化和子树的变化 observer.observe(document.body, { childList: true, subtree: true }); // 首次加载时也尝试执行一次,以防内容已经存在 // 由于MutationObserver可能在初始DOM解析后才触发,直接调用一次确保立即应用 // 稍作延迟,确保页面初始内容渲染完成 setTimeout(() => { const initialModules = document.querySelectorAll('.w-full.overflow-hidden.rounded-lg.border-\\[1\\.5px\\]'); if (initialModules.length > 0) { initialModules.forEach(module => { if (!module.dataset.processed) { const categoryTitles = module.querySelectorAll('div.flex.h-10 > div.text-\\[12px\\]'); const problemItemsInModule = module.querySelectorAll('div.flex.flex-col.border-b-\\[1\\.5px\\] > div.flex.h-\\[52px\\]'); const problemCount = problemItemsInModule.length; categoryTitles.forEach(categoryTitleTextDiv => { if (!categoryTitleTextDiv.querySelector('.problem-count-span')) { const countSpan = document.createElement('span'); countSpan.textContent = ` (${problemCount} 题)`; countSpan.style.marginLeft = '5px'; countSpan.classList.add('problem-count-span'); categoryTitleTextDiv.appendChild(countSpan); } }); problemItemsInModule.forEach((item, index) => { const titleContainer = item.querySelector('div.relative.flex.h-full.w-full.items-center > div.flex.w-0.flex-1.items-center.space-x-2'); if (titleContainer && !titleContainer.querySelector('.problem-index-span')) { const indexSpan = document.createElement('span'); indexSpan.textContent = `${index + 1}. `; indexSpan.classList.add('problem-index-span'); titleContainer.prepend(indexSpan); } }); module.dataset.processed = 'true'; } }); } }, 500); // 延迟 500 毫秒执行,可以根据实际情况调整 })();