* 判断是否应该跳过Stack Overflow网站上的特定元素
(node: any)
| 1108 | * 判断是否应该跳过Stack Overflow网站上的特定元素 |
| 1109 | */ |
| 1110 | function shouldSkipStackOverflowElement(node: any): boolean { |
| 1111 | // 如果当前节点或其祖先节点匹配这些选择器,则跳过 |
| 1112 | const skipSelectors = [ |
| 1113 | // 导航栏 |
| 1114 | 'nav.s-topbar', |
| 1115 | 'div.s-topbar', |
| 1116 | // 侧边栏 |
| 1117 | 'div.s-sidebarwidget', |
| 1118 | // 表单元素 |
| 1119 | 'form', |
| 1120 | 'input', |
| 1121 | 'textarea', |
| 1122 | 'button', |
| 1123 | // 代码块 |
| 1124 | 'pre.s-code-block', |
| 1125 | 'code', |
| 1126 | // 操作按钮 |
| 1127 | 'div.js-voting-container', |
| 1128 | 'div.js-post-menu', |
| 1129 | // 链接和标签 |
| 1130 | 'div.post-taglist', |
| 1131 | 'div.module.community-bulletin', |
| 1132 | // 统计信息 |
| 1133 | 'div.-flair', |
| 1134 | 'div.s-stats', |
| 1135 | 'div.s-badge', |
| 1136 | // 页脚 |
| 1137 | 'footer', |
| 1138 | 'div.site-footer', |
| 1139 | ]; |
| 1140 | |
| 1141 | // 检查当前节点是否匹配跳过选择器 |
| 1142 | for (const selector of skipSelectors) { |
| 1143 | if (node.matches?.(selector)) return true; |
| 1144 | |
| 1145 | // 检查祖先节点 |
| 1146 | let parent = node.parentElement; |
| 1147 | while (parent) { |
| 1148 | if (parent.matches?.(selector)) return true; |
| 1149 | parent = parent.parentElement; |
| 1150 | } |
| 1151 | } |
| 1152 | |
| 1153 | // 检查节点的类名是否包含特定关键字 |
| 1154 | const skipClassKeywords = ['js-', 'icon', 'btn', 'badge', 'vote', 'tag', 's-btn', 'vote-count']; |
| 1155 | |
| 1156 | if (node.className && typeof node.className === 'string') { |
| 1157 | for (const keyword of skipClassKeywords) { |
| 1158 | if (node.className.includes(keyword)) return true; |
| 1159 | } |
| 1160 | } |
| 1161 | |
| 1162 | // 忽略代码片段 |
| 1163 | if (node.tagName?.toLowerCase() === 'pre' || node.tagName?.toLowerCase() === 'code') return true; |
| 1164 | |
| 1165 | // 忽略图标 |
| 1166 | if (node.tagName?.toLowerCase() === 'svg') return true; |
| 1167 |