在全部评论中匹配热门评论并高亮显示,避免重复查看热门评论、精简评论样式、隐藏0赞0反按钮、自动点击更多评论、根据评论总数隐藏一部分低赞低反评论
// ==UserScript==
// @name IT之家移动页面热门评论高亮
// @namespace http://tampermonkey.net/
// @version 1.0.5
// @description 在全部评论中匹配热门评论并高亮显示,避免重复查看热门评论、精简评论样式、隐藏0赞0反按钮、自动点击更多评论、根据评论总数隐藏一部分低赞低反评论
// @author hui-Zz
// @match http*://m.ithome.com/*
// @match http*://bbs.hupu.com/*
// @icon https://www.emojiall.com/en/header-svg/%F0%9F%93%B0.svg
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
/* 站点配置 */
const SITE_CONFIG = {
'm.ithome.com': {
hotCommentSelector: '.hot-comment .placeholder', // 热门评论容器选择器
allCommentSelector: '.all-comment .placeholder', // 全部评论容器选择器
usernameSelector: '.user-name', // 用户名元素选择器
contentSelector: '.user-review', // 评论内容选择器
commentContainerHot: '.hot-comment', // 热门评论区域选择器
commentContainer: '.all-comment', // 全部评论区域选择器
initAction: () => $('.hot-comment').hide() // 初始化操作:隐藏热门评论区域
}
};
// 获取当前站点配置
const hostname = window.location.hostname;
const config = SITE_CONFIG[hostname];
if (!config) return; // 非目标站点直接退出
config.initAction(); // 执行站点初始化操作
/* 工具函数:生成评论唯一标识 */
const getCommentKey = comment => `${comment.username}_${comment.content}`;
/* 核心功能实现 */
class CommentHighlighter {
constructor() {
this.hotComments = new Map(); // 使用Map存储热门评论(O(1)查找)
this.isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
this.commentElementCount = 0;
this.initObservers();
this.collectHotComments(); // 初始收集热门评论
this.highlightComments(); // 初始高亮匹配到的热门评论
}
/* 初始化MutationObserver监听 */
initObservers() {
// 热门评论区域监听
this.observeArea(config.commentContainerHot, () => this.collectHotComments());
// 全部评论区域监听
this.observeArea(config.commentContainer, () => this.highlightComments());
}
/* 通用区域监听方法 */
observeArea(selector, callback) {
const targetNode = document.querySelector(selector);
if (!targetNode) return;
new MutationObserver(() => callback())
.observe(targetNode, {
childList: true, // 监听子元素变化
subtree: true // 监听所有后代元素
});
}
/* 收集热门评论 */
collectHotComments() {
this.hotComments.clear();
document.querySelectorAll(config.hotCommentSelector)
.forEach(commentElement => {
const username = this.getText(commentElement, config.usernameSelector);
const content = this.getText(commentElement, config.contentSelector);
if (username && content) {
this.hotComments.set(getCommentKey({ username, content }), true);
this.processSpecialElements(commentElement); // 处理特殊元素
}
});
}
/* 高亮匹配评论 */
highlightComments() {
this.commentElementCount = (el => el ? parseInt(el.textContent, 10) : 0)(document.querySelector('.comment-number'));
document.querySelectorAll(config.allCommentSelector)
.forEach(commentElement => {
const username = this.getText(commentElement, config.usernameSelector);
const content = this.getText(commentElement, config.contentSelector);
if (hostname === 'm.ithome.com') {
// 点击更多评论
commentElement.querySelector('.look-more')?.click();
// 处理IP显示
this.processHupuIP(commentElement);
const reply = commentElement.querySelector('.reply');
// 始终隐藏回复按钮(🎈想回复评论注释掉下一行代码)
// if (reply) reply.style.display = 'none';
const userfloor = commentElement.querySelector('.user-floor');
const userwritemsg = commentElement.querySelector('.user-write-msg');
const userreview = commentElement.querySelector('.user-review');
userfloor.style.float = 'none';
userfloor.style.marginLeft = '10px';
userwritemsg.style.float = 'right';
userwritemsg.style.marginTop = '-20px';
userreview.style.marginTop = '5px';
// 根据评论总数隐藏一部分低赞低反评论(🎈不隐藏看所有评论注释掉下一行代码)
this.hideComments(commentElement);
}
// 高亮匹配的评论
if (username && content && this.hotComments.has(getCommentKey({ username, content }))) {
commentElement.classList.add('hot-comment-highlight');
}
});
}
/* 隐藏低赞反评论 */
hideComments(commentElement) {
if (hostname === 'm.ithome.com') {
// 获取所有交互元素(安全访问)
const standby = commentElement.querySelector('.stand-by');
const oppose = commentElement.querySelector('.oppose');
const reviewfooter = commentElement.querySelector('.review-footer');
// 根据评论数量确定支持/反对的隐藏阈值
let hideStandbyThreshold = [];
let opposeStandbyThreshold = [];
if (this.commentElementCount < 20) {
// 小于20条,显示所有
hideStandbyThreshold = [];
opposeStandbyThreshold = [];
} else if (this.commentElementCount < 50) {
// 20-50条,隐藏0、1、2
hideStandbyThreshold = [0, 1, 2];
opposeStandbyThreshold = [0, 1, 2];
} else if (this.commentElementCount < 200) {
// 50-200条,隐藏0、1、2、3、4
hideStandbyThreshold = [0, 1, 2, 3, 4];
opposeStandbyThreshold = [0, 1, 2, 3, 4];
} else {
// 大于200条,隐藏10以下
hideStandbyThreshold = Array.from({ length: 10 }, (_, i) => i);
opposeStandbyThreshold = Array.from({ length: 10 }, (_, i) => i);
}
// 处理支持按钮
if (standby) {
const standbyText = standby.textContent?.trim();
const match = standbyText?.match(/支持\((\d+)\)/);
if (match) {
const count = parseInt(match[1]);
if (hideStandbyThreshold.includes(count)) {
standby.style.display = 'none';
}
}
}
// 处理反对按钮
if (oppose) {
const opposeText = oppose.textContent?.trim();
const match = opposeText?.match(/反对\((\d+)\)/);
if (match) {
const count = parseInt(match[1]);
if (opposeStandbyThreshold.includes(count)) {
oppose.style.display = 'none';
}
}
}
// 当支持/反对都符合条件时隐藏底部栏
if (reviewfooter && standby && oppose) {
const standbyText = standby.textContent?.trim();
const opposeText = oppose.textContent?.trim();
const standbyMatch = standbyText?.match(/支持\((\d+)\)/);
const opposeMatch = opposeText?.match(/反对\((\d+)\)/);
if (standbyMatch && opposeMatch) {
const standbyCount = parseInt(standbyMatch[1]);
const opposeCount = parseInt(opposeMatch[1]);
if (hideStandbyThreshold.includes(standbyCount) && opposeStandbyThreshold.includes(opposeCount)) {
reviewfooter.style.display = 'none';
var hasDeputyFloor = commentElement.querySelector('li.placeholder.deputy-floor');
if (!hasDeputyFloor && commentElement.classList.contains('placeholder') && commentElement.classList.contains('main-floor')) {
// 隐藏当前符合隐藏条件并且没有回复的评论
commentElement.style.display = 'none';
}
}
}
}
}
}
/* 辅助方法:安全获取文本内容 */
getText(element, selector) {
return element.querySelector(selector)?.textContent?.trim();
}
/* 处理IP地址显示 */
processHupuIP(element) {
const ipElement = element.querySelector('.user-ip');
const ipText = ipElement?.textContent?.trim();
const match = ipText?.match(/IT之家(.*?)网友/);
if (match) ipElement.textContent = match[1];
}
/* 处理站点特殊元素 */
processSpecialElements(element) {
// IT之家特殊处理(示例)
if (hostname === 'm.ithome.com') {
element.style.display = 'block';
}
}
}
/* 样式注入 */
const style = document.createElement('style');
style.textContent = `
.hot-comment-highlight {
background-color: yellow !important;
border: 2px solid orange !important;
}
@media (prefers-color-scheme: dark) {
.hot-comment-highlight {
background-color: #333 !important;
color: #fff !important;
}
}
`;
document.head.appendChild(style);
// 启动高亮系统
new CommentHighlighter();
})();