首页 / 资讯中心 / 文章详情

洛谷团队一键@所有人神器:纯前端脚本实现与踩坑指南

洛谷团队一键@所有人神器:纯前端脚本实现与踩坑指南 ★ FEATURED ARTICLE
如果你管过洛谷团队一定懂我说的这个痛团队群里要发一条重要通知但评论区根本没有“所有人”这个按钮。以前我管理一个一百多人的刷题团队每次喊人看公告、催作业、发洛谷p14258题解都得手动把成员名单从头翻到尾一个一个翻到后面手指都麻了还经常漏人。于是我写了个“洛谷团队一键所有人神器”本质是一个跑在浏览器里的脚本在团队页面挂一个悬浮按钮点一下自动抓取全队成员昵称拼成一条完整的文本复制到剪贴板你切到讨论区粘贴发布整队通知就出去了。这东西不碰后端、不涉及私密数据纯前端实现适合所有洛谷团队管理员、教练和刷题群群主。1. 项目概述为什么需要这个“一键所有人”神器1.1 洛谷团队管理的真实痛点洛谷的团队功能做得其实不差公告、团队文件、团队讨论、作业系统都有唯独在“群发通知”这一步差了点意思。团队讨论区和公告评论里你只能通过“”手动点名具体成员没有一个类似QQ群“全体成员”的入口。团队人少的时候还好十几个成员眼睛扫一遍就点完了。但团队一旦超过五十人这个操作就变成体力活先翻成员列表记住哪些人常来哪些人已经好久没上线还得注意别漏掉刚加入的新人。一百人以上光是把昵称找齐就够呛更别提拼完一长串文本还要注意别超出发送限制。我见过最离谱的一次是团队里有人分享了一份“洛谷300精析下载”的网盘资源管理员想通知全队去领结果被迫发了七条回复每条下面二十几个人。后面新成员加入又得补发一轮。这已经不是效率问题了是纯粹的折磨。1.2 四套候选方案我为什么最后选了浏览器脚本开始动手之前我把能想到的方案列了一遍各有取舍方案优点缺点推荐度纯手动复制粘贴零门槛啥都不用装几百人时累死人易漏不推荐后端脚本调洛谷接口理论上一键全自动要处理登录态、签名参数、风控还得有服务器坑太多浏览器控制台临时脚本免安装立刻能用每次要复制代码非技术成员不会用适合自己临时用油猴脚本悬浮按钮装一次长期可用一键触发需要装浏览器扩展初次配置有学习成本最推荐我最终的选型很明确自己日常用控制台脚本给团队助教和教练配油猴脚本。两种其实共用同一套核心逻辑只是外壳不同。前者灵活后者友好。为什么不碰后端方案洛谷的接口不是公开的很多请求带签名校验你去模拟登录态和请求头很容易触发风控代码写出来大概率用不了几次就废了。泡泡面的时候老实烧水别想着修仙把“取出成员昵称”这件事放在浏览器里做是最贴近现实的做法。2. 实现原理拆解所有人的底层逻辑2.1 成员数据从哪来接口与页面渲染想拼出所有人的文本第一步得拿到“所有人的昵称”。洛谷团队页面的“成员”标签页会展示完整成员列表但这份数据是怎么来的用开发者工具看网络请求你会发现前端在进入成员页时会向后端要一次成员列表。理论上我直接调这个接口拿JSON最干净但实际一看就放弃了请求地址带签名参数token可能是动态生成的我懒得研究也没必要。页面已经把昵称渲染成DOM节点了直接抓页面元素不就行了所以我的思路很简单打开团队“成员”标签页让脚本自动模拟点击“加载更多”按钮如果有分页把列表一次性铺开然后从页面DOM里把所有成员昵称节点抠出来。这招有点土但极其稳——只要页面能把成员显示出来脚本就能抓到完全不依赖任何内部接口约定。2.2 “”机制的真相与复制粘贴策略这里有个新手最容易踩的坑用JavaScript直接往洛谷的输入框里塞值然后模拟提交很多时候发出去就是纯文本成员根本收不到“提到”通知。核心原因在于洛谷的输入是带交互的你输入一个“”会弹出成员补全列表选中的那一刻编辑器内部会把“昵称”和“被的用户身份”关联起来。如果你绕过补全交互直接把xxx文本塞进去编辑器可能不会把它识别成真正的“提到某人”。所以我从一开始就没打算“程序直接代发”而是定了一个保险的策略脚本只负责“生成并复制”真正的发布动作由人来做。你把文本粘贴到输入框后这属于一个真实的粘贴事件至少能进入编辑器内容发布前如果需要再手动微调一下让编辑器重新解析。这个策略牺牲了一点点自动化换来了极高的兼容性一般团队里用完全够了。2.3 整体流程与模块划分整个脚本的流程可以拆成四个模块加载器循环点击“加载更多”直到所有成员渲染完毕。收集器按选择器抓取昵称节点去除空值和重复项。拼接器把昵称数组拼成昵称1 昵称2 昵称3 ...这样的字符串。剪贴板模块优先用navigator.clipboard失败则回退到document.execCommand(copy)。代码写起来不复杂难的是边界情况。比如团队几百人加载列表要循环点好几次按钮比如有人昵称里带空格拼出来会不会被错误截断比如浏览器不给剪贴板权限怎么办。这些细节我会在下一节全部摊开讲。3. 实操脚本从0到1完整落地3.1 控制台版脚本最简方案先给一个最直接的版本。打开洛谷团队页面切到“成员”标签页按F12进入开发者工具切到Console控制台粘贴以下代码回车(async () { // 配置区 // 成员昵称所在节点的选择器按自己页面实际结构改 const MEMBER_SELECTOR .team-member-item .name; // “加载更多”按钮的选择器没有分页的话保持原样 const LOAD_MORE_SELECTOR .team-member-load-more; // const sleep (ms) new Promise(resolve setTimeout(resolve, ms)); // 1. 循环点击“加载更多”最多点50次避免死循环 for (let i 0; i 50; i) { const btn document.querySelector(LOAD_MORE_SELECTOR); if (!btn) break; btn.click(); await sleep(800); } // 2. 收集成员昵称 const nodes document.querySelectorAll(MEMBER_SELECTOR); const names [...nodes].map(el el.textContent.trim()).filter(Boolean); if (names.length 0) { alert(没有抓到成员请先进入“成员”标签页再检查选择器); return; } // 3. 拼成 文本 const text names.map(name name).join( ); // 4. 复制到剪贴板 try { await navigator.clipboard.writeText(text); } catch (e) { const ta document.createElement(textarea); ta.value text; document.body.appendChild(ta); ta.select(); document.execCommand(copy); document.body.removeChild(ta); } console.log(共抓取成员 names.length 人已复制到剪贴板); })();把这串代码保存成一个片段以后每次要用F12粘贴运行就成了。这段代码最需要注意的地方是选择器.team-member-item .name是我项目里的写法不同时间、不同皮肤的洛谷页面类名可能有差异。如果你粘贴运行后alert提示没抓到成员直接跳到3.4花三分钟重新定位选择器。3.2 油猴脚本版一键按钮控制台脚本自己用没问题但你不可能让团队里每个助教都去开F12粘贴代码。这时候油猴脚本Tampermonkey就派上用场了。先装好油猴扩展然后新建一个脚本粘贴下面的内容// UserScript // name 洛谷团队一键所有人 // namespace luogu-team-mention-all // version 1.0.0 // description 在洛谷团队页面生成“一键所有人”悬浮按钮 // author YourName // match https://www.luogu.com.cn/team/* // grant none // /UserScript (function () { use strict; // 配置区 const MEMBER_SELECTOR .team-member-item .name; const LOAD_MORE_SELECTOR .team-member-load-more; // const sleep (ms) new Promise(resolve setTimeout(resolve, ms)); async function copyMentionAll() { // 循环点“加载更多” for (let i 0; i 50; i) { const btn document.querySelector(LOAD_MORE_SELECTOR); if (!btn) break; btn.click(); await sleep(800); } const nodes document.querySelectorAll(MEMBER_SELECTOR); const names [...nodes].map(el el.textContent.trim()).filter(Boolean); if (names.length 0) { alert(没有抓到成员请先进入成员标签页再检查选择器); return; } const text names.map(name name).join( ); try { await navigator.clipboard.writeText(text); } catch (e) { const ta document.createElement(textarea); ta.value text; document.body.appendChild(ta); ta.select(); document.execCommand(copy); document.body.removeChild(ta); } alert(已复制 names.length 位成员请在讨论区粘贴发布); } function init() { const btn document.createElement(button); btn.textContent 一键所有人; btn.style.cssText position:fixed;left:20px;bottom:80px;z-index:99999; padding:8px 14px;background:#4a90d9;color:#fff;border:none; border-radius:4px;font-size:14px;cursor:pointer;; btn.addEventListener(click, copyMentionAll); document.body.appendChild(btn); } if (document.readyState loading) { document.addEventListener(DOMContentLoaded, init); } else { init(); } })();油猴脚本和控制台版的差别只在“外壳”油猴通过match规则在luogu.com.cn/team开头也就是团队相关的页面自动运行在页面右下角挂一个浮动按钮。点按钮它自动切到成员逻辑复制完弹窗提示你去粘贴。注意我脚本里grant none的意思是放行页面原生API如果你在用的时候发现剪贴板受权限限制也可以把grant改成GM_setClipboard然后把复制那段换成GM_setClipboard(text)。两种方式我都试过后者在油猴环境下更不容易碰到权限问题。3.3 成员太多分批发车模式我团队超过两百人之后遇到了一个更现实的问题一次复制的文本太长粘贴进讨论区后发布直接被吞。这时候就需要“分批发车”模式。逻辑很简单抓完成员名单后不要一次性拼一条巨无霸文本而是按批次切割每批复制一次你发完一条再点“下一批”// 分批发车batchSize为每批人数 async function copyMentionAllInBatches(batchSize 50) { // 收集 names 的代码同上一版这里省略 const total names.length; const batchTotal Math.ceil(total / batchSize); for (let i 0; i total; i batchSize) { const batch names.slice(i, i batchSize); const text batch.map(name name).join( ); await navigator.clipboard.writeText(text); alert(第 ${i / batchSize 1} 批已复制共 ${batchTotal} 批赶紧粘贴发布发完再点确定复制下一批); } }实际用法是点“一键所有人”按钮弹窗提示“第1批已复制”你切到讨论区粘贴发送再切回来点确定继续复制第2批。批大小建议50左右既不会短得频繁切来切去也不会长得触发发布限制。3.4 选择器失效怎么办3分钟定位新选择器这是整个项目里最容易被忽略、也是最让人头疼的环节。洛谷前端只要改过一次版原来写的类名可能就变了脚本直接失效。定位方法很简单打开团队“成员”标签页在某个成员昵称上右键选择“检查”Inspect。开发者工具里高亮的那块DOM就是昵称节点。看它的class或者父级的class挑一个精准、短小的选择器写进配置区。换好之后怎么验证在Console里输入一行命令document.querySelectorAll(你改好的选择器).length如果返回的数字跟你肉眼看到的成员数差不多说明选择器没问题脚本可以正常跑。记住别选太宽泛的类名比如就写一个.name容易把页面其他地方的“名字”也抓进来。4. 踩坑记录常见问题与排查实录4.1 粘贴后成员收不到通知我最早做这个脚本就是冲着“省事”去的结果第一次用就翻车了。复制了一长串昵称发布之后确实显示了所有人的名字但团队成员在消息列表里根本看不到“有人提到我”的小红点。后来我反复测试确认了洛谷的通知很多情况下依赖“输入时从补全列表里选人”这个动作。你直接粘贴纯文本系统可能只把它当普通文字处理。所以我不建议完全无脑复制粘贴发送。稳妥的做法是粘贴完成后在编辑器里把光标移到某个昵称后面删掉一个字符再重新打出来让补全列表弹出来选一次这样至少能保证一部分核心成员收到通知。如果是几十人的小团队我反而推荐手动操作——反正一眼扫得完。几百人的团队你只能权衡要么用脚本批量接受部分成员收不到通知的现实要么手动核心成员普通成员靠公告提醒。没有完美方案。4.2 文本超长无法发布这个坑我在3.3里已经预告了。洛谷帖子和回复有字数限制几百个昵称拼起来动辄上千字超过限制后发送按钮会直接变灰或者点了没反应。分批复制是唯一靠谱的办法但要注意节奏别一次性把所有批次复制完复制完不粘贴下一批就会把上一批覆盖掉。老老实实“复制一批→发一批→回来点确定→再复制下一批”流程虽然笨但不会乱。另外一个偏方如果成员昵称比较长可以在拼接时去掉昵称中的空格和特殊符号只保留核心ID文字。但这样做风险是发出的文本跟实际昵称不匹配通知就更难触发了所以我不建议对长昵称做清洗。4.3 复制功能在不同浏览器的兼容性navigator.clipboard.writeText这个API在HTTPS页面下才能用而且有些浏览器会弹权限询问框用户不点允许就一直失败。洛谷本身是HTTPS一般没问题但如果你在本地调试、或者在部分套壳浏览器里跑就会翻车。我的处理办法是写一个双保险优先用新API失败就创建一个隐藏的textarea选中后执行老牌的document.execCommand(copy)。这个方法兼容性极好从Chrome到Edge到Safari都能跑。油猴环境下还有一个选择用GM_setClipboard。它直接调用油猴扩展的剪贴板能力不依赖页面本身的权限稳定得很。代价是grant不能为none了得显式声明。4.4 脚本用两天就失效了“昨天还好好的今天怎么按钮点着没反应”这类问题我遇到太多次了绝大多数情况不是你代码写错了而是洛谷前端更新了DOM结构或者改成了懒加载。排查步骤我建议按顺序来打开Console面板看有没有红色报错有的话把报错信息贴出来基本能定位到哪一行挂了。看“加载更多”按钮是不是还在。如果按钮都没了说明分页逻辑改了可能改成了滚动自动加载那我的固定代码就要调整成滚动监听。确认你用的选择器还有没有匹配到元素。用3.4里的验证命令看数量。还有一个容易被忽略的点洛谷有时会在团队页面走CDN缓存你本地开着一个旧页面跑脚本抓到的其实是过期DOM。这种时候强制刷新一下页面就行。5. 扩展玩法与使用建议5.1 从一键扩展到定时提醒主力脚本稳定之后我又做了两个小变体。一个是“定时复制”用setTimeout包一层在每天固定时间自动执行收集和复制比如每周五晚上提醒大家交作业。这个适合那种“规律性通知”的场景前提是电脑得开着、页面得挂着自动化程度有限。另一个变体是“只未完成成员”。洛谷团队有作业系统你可以先通过页面筛选出未交作业的成员列表再用脚本抓取这部分人拼成文本。抓取原理不变改一下收集器的选择器就够了。这个功能我后来用得最多比无差别所有人温和得多也不会让已经完成任务的人觉得被骚扰。5.2 真实使用中的尺度和建议所有人是强提醒用多了人人是会麻木的。我在自己团队里定了个不成文的规矩只有发布题解资源、调整团队章程、通知比赛时间这三类事情才允许用批量其余讨论一律走普通消息。脚本只是工具真正的价值在于怎么用它维护团队氛围。另外多说一句脚本里的成员名单是实时从页面抓的所以新成员加入之后不需要手动维护名单天然就是最新的。这一点比我最初预想的要方便很多。如果你也是那种管着一个五十人以上洛谷团队的人这个神器应该能帮你省下不少重复劳动。
阅读完成 · 觉得有帮助?
咨询建站