|
|
Cynnie 发表于 2026-8-26 11:19
感谢
bug喜+1
这里无法完整预览别人的回复,而且别人的回复中如果带图片也没办法看哦
而且消息通知列表里是分页数的,论坛APP好像还不能自动加载下一页
这一点从已过滤消息数量上就能看出来的
这是我的脚本
这是论坛APP
最后脚本可能对你有用,给你参考参考
- // ==UserScript==
- // [url=home.php?mod=space&uid=121064]@name[/url] [MT论坛]消息预览++
- // @namespace https://github.com/qcxs/mtbbs
- // @version 2026-06-15
- // @description 基于青春向上大佬的消息预览和自动加载进行优化修改,增加和优化了消息过滤功能。
- // @author 青春向上&秋枫Mod
- // @match *://bbs.binmt.cc/home.php?mod=space&do=notice*
- // @match *://bbs.binmt.cc/home.php?*type=reply*
- // @icon https://bbs.binmt.cc/favicon.ico
- // @grant none
- // @run-at document-idline
- // @license MIT
- // ==/UserScript==
- (async function () {
- 'use strict';
- // ==================== 全局配置和工具函数 ====================
-
- const urlObj = new URL(window.location.href);
- const searchParams = urlObj.searchParams;
- const phpFile = urlObj.pathname.split('/').pop();
-
- async function fetchReplyRoot(url, timeout = 3000) {
- try {
- const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
- if (!res.ok) return '';
- const xml = new DOMParser().parseFromString(await res.text(), 'text/xml');
- return xml.querySelector('root')?.textContent || '';
- } catch {
- return '';
- }
- }
- // ==================== 消息提醒预览功能 ====================
-
- const PREVIEW_CONFIG = {
- PROCESSED_MARK: 'mt-preview-processed',
- notice: {
- noticeSelector: '.comiis_notice_list>ul',
- selectContent: 'div.comiis_messages',
- validCheck: 'a.lit[href*="goto=findpost"]',
- MAX_CACHE_COUNT: 100,
- CACHE_STORAGE_KEY: 'mt_bbs_preview_cache',
- REQUEST_DELAY: 100
- },
- postReply: {
- threadSelector: '.comiis_forumlist>ul',
- threadASelector: '.mmlist_li_box a',
- validCheck: '.mmlist_li_box a',
- loadedMark: 'replyLoaded'
- },
- filter: {
- FILTER_STORAGE_KEY: 'mt_bbs_filter_keywords',
- FILTERED_MARK: 'mt-filtered-hidden',
- FILTERED_CLASS: 'mt-filtered-item',
- SETTINGS_MARK: 'mt-filter-settings'
- }
- };
- // 过滤器相关函数
- function getFilterKeywords() {
- try {
- const data = localStorage.getItem(PREVIEW_CONFIG.filter.FILTER_STORAGE_KEY);
- if (!data) return [];
- return data.split('\n').map(s => s.trim()).filter(s => s.length > 0);
- } catch { return []; }
- }
- function saveFilterKeywords(keywords) {
- localStorage.setItem(PREVIEW_CONFIG.filter.FILTER_STORAGE_KEY, keywords.join('\n'));
- }
- function shouldFilter(content) {
- const keywords = getFilterKeywords();
- if (!keywords.length) return false;
- return keywords.some(kw => content.includes(kw));
- }
- function updateFilterButton() {
- const btn = document.getElementById('mt-filter-toggle-btn');
- if (!btn) return;
- const count = document.querySelectorAll(`li.${PREVIEW_CONFIG.filter.FILTERED_CLASS}`).length;
- btn.textContent = `已过滤消息(${count})`;
- }
- function toggleFilteredMessages() {
- const btn = document.getElementById('mt-filter-toggle-btn');
- if (!btn) return;
- const items = document.querySelectorAll(`li.${PREVIEW_CONFIG.filter.FILTERED_CLASS}`);
- const isCurrentlyHidden = btn.dataset.showing === 'true';
- if (isCurrentlyHidden) {
- items.forEach((li, index) => {
- li.style.transition = `opacity 0.3s ease, transform 0.3s ease, max-height 0.3s ease`;
- li.style.opacity = '0';
- li.style.transform = 'translateY(-10px)';
- li.style.maxHeight = '0';
- li.style.marginBottom = '0';
-
- setTimeout(() => {
- li.style.display = 'none';
- li.setAttribute(PREVIEW_CONFIG.filter.FILTERED_MARK, 'true');
- }, 300);
- });
-
- setTimeout(() => {
- btn.dataset.showing = 'false';
- btn.textContent = `已过滤消息(${items.length})`;
- btn.style.color = '#53bcf5';
-
- // 切换后检查是否需要自动加载
- setTimeout(checkAndLoadNext, 500);
- }, 300);
- } else {
- items.forEach((li, index) => {
- li.style.display = '';
- li.style.transition = `opacity 0.3s ease, transform 0.3s ease, max-height 0.3s ease`;
- li.style.opacity = '0';
- li.style.transform = 'translateY(-10px)';
- li.style.maxHeight = '0';
- li.style.marginBottom = '0';
-
- setTimeout(() => {
- li.style.opacity = '1';
- li.style.transform = 'translateY(0)';
- li.style.maxHeight = '500px';
- li.style.marginBottom = '8px';
- }, index * 50);
- });
-
- btn.dataset.showing = 'true';
- btn.textContent = `收起已过滤消息(${items.length})`;
- btn.style.color = '#e6a23c';
- }
- }
- function createReplyDialog(replyUrl, tid, pid) {
- const existingDialog = document.getElementById('mt-reply-dialog');
- if (existingDialog) existingDialog.remove();
- const dialog = document.createElement('div');
- dialog.id = 'mt-reply-dialog';
- dialog.style.cssText = `
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 9999;
- background: #fff;
- display: flex;
- flex-direction: column;
- opacity: 0;
- transition: opacity 0.3s ease-out;
- `;
- dialog.innerHTML = `
- <div style="display:flex;justify-content:space-between;align-items:center;padding: 12px 16px; border-bottom: 1px solid #eee; background:#f7f8fa;">
- <strong style="font-size:16px; font-weight:600; color:#333;">回复</strong>
- <span style="cursor:pointer;font-size:24px;color:#999; line-height:1;" id="mt-reply-close">×</span>
- </div>
- <div id="mt-reply-iframe-container" style="flex: 1; overflow-y: auto;">
- </div>
- `;
- document.body.appendChild(dialog);
- const overlay = document.createElement('div');
- overlay.id = 'mt-reply-overlay';
- overlay.style.cssText = `
- position: fixed;
- top: 0; left: 0; right: 0; bottom: 0;
- z-index: 9998;
- background: rgba(0,0,0,0.4);
- backdrop-filter: blur(2px);
- opacity: 0;
- transition: opacity 0.3s ease-out;
- `;
- overlay.onclick = closeReplyDialog;
- document.body.appendChild(overlay);
- setTimeout(() => {
- dialog.style.opacity = '1';
- overlay.style.opacity = '1';
- }, 10);
- document.getElementById('mt-reply-close').onclick = closeReplyDialog;
- const iframeContainer = document.getElementById('mt-reply-iframe-container');
- const iframe = document.createElement('iframe');
- iframe.src = replyUrl;
- iframe.style.cssText = `
- width: 100%;
- height: 100%;
- border: none;
- min-height: 60vh;
- `;
- iframeContainer.appendChild(iframe);
- }
- function closeReplyDialog() {
- const dialog = document.getElementById('mt-reply-dialog');
- const overlay = document.getElementById('mt-reply-overlay');
-
- if (dialog) {
- dialog.style.opacity = '0';
- }
- if (overlay) {
- overlay.style.opacity = '0';
- }
- setTimeout(() => {
- if (dialog) {
- dialog.remove();
- }
- if (overlay) {
- overlay.remove();
- }
- }, 300);
- }
- function createFilterToolbar() {
- if (document.getElementById('mt-filter-toolbar')) return;
- const toolbar = document.createElement('div');
- toolbar.id = 'mt-filter-toolbar';
- toolbar.style.cssText = `
- display: flex;
- gap: 8px;
- align-items: center;
- padding: 8px 12px;
- margin-bottom: 10px;
- background: #f7f8fa;
- border-radius: 6px;
- border: 1px solid #e8e8e8;
- `;
- const settingsBtn = document.createElement('button');
- settingsBtn.id = 'mt-filter-settings-btn';
- settingsBtn.textContent = '⚙ 过滤设置';
- settingsBtn.style.cssText = `
- padding: 5px 12px;
- border: 1px solid #53bcf5;
- background: #fff;
- color: #53bcf5;
- border-radius: 4px;
- cursor: pointer;
- font-size: 13px;
- `;
- settingsBtn.onclick = () => toggleFilterSettings();
- const toggleBtn = document.createElement('button');
- toggleBtn.id = 'mt-filter-toggle-btn';
- toggleBtn.textContent = '已过滤消息(0)';
- toggleBtn.dataset.showing = 'false';
- toggleBtn.style.cssText = `
- padding: 5px 12px;
- border: 1px solid #e6a23c;
- background: #fff;
- color: #53bcf5;
- border-radius: 4px;
- cursor: pointer;
- font-size: 13px;
- transition: all 0.2s ease;
- `;
- toggleBtn.onclick = toggleFilteredMessages;
-
- toggleBtn.addEventListener('mouseenter', () => {
- toggleBtn.style.backgroundColor = '#f0f0f0';
- });
- toggleBtn.addEventListener('mouseleave', () => {
- toggleBtn.style.backgroundColor = '#fff';
- });
- toolbar.appendChild(settingsBtn);
- toolbar.appendChild(toggleBtn);
- const container = document.querySelector(PREVIEW_CONFIG.notice.noticeSelector);
- if (container) {
- container.parentNode.insertBefore(toolbar, container);
- }
- }
- let filterSettingsPanel = null;
- let originalOverflow = '';
- function toggleFilterSettings() {
- if (filterSettingsPanel && filterSettingsPanel.parentNode) {
- closeFilterSettings();
- return;
- }
- originalOverflow = document.body.style.overflow;
- document.body.style.overflow = 'hidden';
- filterSettingsPanel = document.createElement('div');
- filterSettingsPanel.id = 'mt-filter-settings-panel';
- filterSettingsPanel.style.cssText = `
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%) scale(0.95);
- z-index: 9999;
- background: #fff;
- border: 1px solid #53bcf5;
- border-radius: 6px;
- width: 90%;
- max-width: 500px;
- max-height: 80vh;
- overflow-y: auto;
- box-shadow: 0 4px 12px rgba(0,0,0,0.1);
- opacity: 0;
- transition: all 0.3s ease-out;
- `;
- const keywords = getFilterKeywords();
- filterSettingsPanel.innerHTML = `
- <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px; padding: 16px 20px 0;">
- <strong style="font-size:15px; font-weight:600; color:#333;">评论过滤设置</strong>
- <span style="cursor:pointer;font-size:22px;color:#999; line-height:1;" id="mt-filter-close">×</span>
- </div>
- <p style="font-size:12px;color:#999;margin:0 0 8px 0; padding: 0 20px;">每行一个关键词,包含该关键词的消息将被隐藏</p>
- <textarea id="mt-filter-keywords-input" style="
- width: calc(100% - 40px);
- height: 200px;
- margin: 0 20px;
- padding: 12px;
- border: 1px solid #ddd;
- border-radius: 4px;
- font-size: 14px;
- resize: vertical;
- box-sizing: border-box;
- line-height: 1.5;
- font-family: inherit;
- ">${keywords.join('\n')}</textarea>
- <div style="display:flex;justify-content:flex-end;align-items:center;margin-top:12px; padding: 0 20px 16px;">
- <span style="font-size:12px;color:#999;">输入后自动保存</span>
- </div>
- `;
- document.body.appendChild(filterSettingsPanel);
- const overlay = document.createElement('div');
- overlay.id = 'mt-filter-overlay';
- overlay.style.cssText = `
- position: fixed;
- top: 0; left: 0; right: 0; bottom: 0;
- z-index: 9998;
- background: rgba(0,0,0,0.4);
- backdrop-filter: blur(2px);
- opacity: 0;
- transition: opacity 0.3s ease-out;
- `;
- overlay.onclick = closeFilterSettings;
- document.body.appendChild(overlay);
- setTimeout(() => {
- filterSettingsPanel.style.transform = 'translate(-50%, -50%) scale(1)';
- filterSettingsPanel.style.opacity = '1';
- overlay.style.opacity = '1';
- }, 10);
- document.getElementById('mt-filter-close').onclick = closeFilterSettings;
- const keywordsInput = document.getElementById('mt-filter-keywords-input');
- keywordsInput.addEventListener('input', autoSaveKeywords);
- }
- function autoSaveKeywords() {
- const text = document.getElementById('mt-filter-keywords-input').value;
- const kws = text.split('\n').map(s => s.trim()).filter(s => s.length > 0);
- saveFilterKeywords(kws);
- reapplyFilter();
- }
- function closeFilterSettings() {
- if (!filterSettingsPanel) return;
- document.body.style.overflow = originalOverflow;
- filterSettingsPanel.style.transform = 'translate(-50%, -50%) scale(0.95)';
- filterSettingsPanel.style.opacity = '0';
- const overlay = document.getElementById('mt-filter-overlay');
- if (overlay) {
- overlay.style.opacity = '0';
- }
- setTimeout(() => {
- if (filterSettingsPanel) {
- filterSettingsPanel.remove();
- filterSettingsPanel = null;
- }
- if (overlay) {
- overlay.remove();
- }
- }, 300);
- }
- function reapplyFilter() {
- const keywords = getFilterKeywords();
- const allItems = document.querySelectorAll('li');
- allItems.forEach(li => {
- if (!li.hasAttribute(PREVIEW_CONFIG.PROCESSED_MARK)) return;
- const contentEl = li.querySelector('.comiis_messages');
- if (!contentEl) return;
- const content = contentEl.innerText || '';
- if (keywords.length === 0) {
- li.classList.remove(PREVIEW_CONFIG.filter.FILTERED_CLASS);
- li.style.display = '';
- li.removeAttribute(PREVIEW_CONFIG.filter.FILTERED_MARK);
- removeFilterBadge(li);
- } else if (keywords.some(kw => content.includes(kw))) {
- if (!li.classList.contains(PREVIEW_CONFIG.filter.FILTERED_CLASS)) {
- li.classList.add(PREVIEW_CONFIG.filter.FILTERED_CLASS);
- }
- if (li.getAttribute(PREVIEW_CONFIG.filter.FILTERED_MARK) !== 'true') {
- li.style.display = 'none';
- li.setAttribute(PREVIEW_CONFIG.filter.FILTERED_MARK, 'true');
- }
- addFilterBadge(li);
- } else {
- li.classList.remove(PREVIEW_CONFIG.filter.FILTERED_CLASS);
- li.style.display = '';
- li.removeAttribute(PREVIEW_CONFIG.filter.FILTERED_MARK);
- removeFilterBadge(li);
- }
- });
- updateFilterButton();
-
- // 过滤后检查是否需要自动加载
- setTimeout(checkAndLoadNext, 500);
- }
- function applyFilterToItem(li, content) {
- if (shouldFilter(content)) {
- li.classList.add(PREVIEW_CONFIG.filter.FILTERED_CLASS);
- li.style.display = 'none';
- li.setAttribute(PREVIEW_CONFIG.filter.FILTERED_MARK, 'true');
- addFilterBadge(li);
- updateFilterButton();
- return true;
- }
- removeFilterBadge(li);
- return false;
- }
- function addFilterBadge(li) {
- if (li.querySelector('.mt-filter-badge')) return;
- const badge = document.createElement('span');
- badge.className = 'mt-filter-badge';
- badge.textContent = '已过滤';
- badge.style.cssText = `
- position: absolute;
- bottom: 6px;
- right: 6px;
- color: #f56c6c;
- background: #fff;
- border: 1px solid #f56c6c;
- font-size: 11px;
- font-weight: 500;
- padding: 2px 6px;
- border-radius: 3px;
- z-index: 10;
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
- `;
- if (getComputedStyle(li).position === 'static') {
- li.style.position = 'relative';
- }
- li.appendChild(badge);
- }
- function removeFilterBadge(li) {
- const badge = li.querySelector('.mt-filter-badge');
- if (badge) {
- badge.remove();
- }
- }
- function initCommonListObserver(containerSel, itemSel, validCheck, callback) {
- const container = document.querySelector(containerSel);
- if (!container) {
- console.log('监听失败,没有帖子!')
- return;
- }
- document.querySelectorAll(itemSel).forEach(el => {
- if (validCheck(el))
- callback(el)
- });
- const observer = new MutationObserver(muts => {
- muts.forEach(mut => {
- mut.addedNodes.forEach(node => {
- if (node.nodeType === 1 && node.matches(itemSel)) {
- if (validCheck(node)) callback(node);
- }
- });
- });
- });
- observer.observe(container, { childList: true, subtree: false });
- }
- async function initNoticePreview() {
- const cfg = PREVIEW_CONFIG.notice;
- createFilterToolbar();
- let cacheList = [];
- try {
- const data = localStorage.getItem(cfg.CACHE_STORAGE_KEY);
- if (data) {
- const parsed = JSON.parse(data);
- if (Array.isArray(parsed)) {
- cacheList = parsed;
- } else {
- throw new Error('缓存格式有误,自动重置!')
- }
- }
- } catch (e) {
- console.log('发生错误:', e)
- localStorage.removeItem(cfg.CACHE_STORAGE_KEY);
- cacheList = [];
- }
- const requestQueue = [];
- let isQueueRunning = false;
- initCommonListObserver(cfg.noticeSelector, `${cfg.noticeSelector}>li`,
- li => !li.hasAttribute(PREVIEW_CONFIG.PROCESSED_MARK) && li.querySelector(cfg.validCheck),
- li => {
- if (!li.hasAttribute(PREVIEW_CONFIG.PROCESSED_MARK)) {
- processNoticeItem(li);
- }
- });
- function processNoticeItem(li) {
- li.setAttribute(PREVIEW_CONFIG.PROCESSED_MARK, 'true');
- const viewLink = li.querySelector(cfg.validCheck);
- if (!viewLink) return;
- const { tid, pid } = getTidPidFromUrl(viewLink.href);
- if (!tid || !pid) return;
- const cacheKey = `${tid}_${pid}`;
- const cacheData = cacheList.find(item => item.key === cacheKey);
- if (cacheData) {
- insertContentToLi(li, cacheData.content, cacheData.replyHref, tid, pid);
- applyFilterToItem(li, cacheData.content);
- } else {
- requestQueue.push({ li, tid, pid, cacheKey });
- if (!isQueueRunning) runQueue();
- }
- }
- async function runQueue() {
- if (requestQueue.length === 0) { isQueueRunning = false; return; }
- isQueueRunning = true;
- const task = requestQueue.shift();
- try {
- const url = `https://bbs.binmt.cc/forum.php?mod=viewthread&tid=${task.tid}&viewpid=${task.pid}&mobile=2&inajax=1`;
- const rootHtml = await fetchReplyRoot(url);
- const result = parseContentAndReplyHref(rootHtml);
- insertContentToLi(task.li, result.content, result.replyHref, task.tid, task.pid);
- applyFilterToItem(task.li, result.content);
- if (result.content && !result.content.includes('失败') && !result.content.includes('[空内容]')) {
- cacheList = cacheList.filter(item => item.key !== task.cacheKey);
- cacheList.unshift({ key: task.cacheKey, ...result, time: Date.now() });
- if (cacheList.length > cfg.MAX_CACHE_COUNT) cacheList = cacheList.slice(0, cfg.MAX_CACHE_COUNT);
- localStorage.setItem(cfg.CACHE_STORAGE_KEY, JSON.stringify(cacheList));
- }
- } catch (e) {
- insertContentToLi(task.li, '[加载失败]', '', task.tid, task.pid);
- } finally {
- setTimeout(runQueue, cfg.REQUEST_DELAY);
- }
- }
- function getTidPidFromUrl(url) {
- const p = new URLSearchParams(url);
- return { tid: p.get('ptid'), pid: p.get('pid') };
- }
- function parseContentAndReplyHref(rootHtml) {
- try {
- if (!rootHtml) return { content: '[获取失败]', replyHref: '' };
- const div = document.createElement('div');
- div.innerHTML = rootHtml;
- const content = div.querySelector(cfg.selectContent)?.innerHTML?.trim() || '[空内容]';
- const replyHref = div.querySelector('a[href*="action=reply"]')?.href || '';
- div.remove();
- return { content, replyHref };
- } catch { return { content: '[解析失败]', replyHref: '' }; }
- }
- function insertContentToLi(li, html, replyHref, tid, pid) {
- const box = document.createElement('div');
- box.style.width = '100%';
- li.appendChild(box);
- const root = box.attachShadow({ mode: 'open' });
- root.innerHTML = `
- <style>
- .comiis_postli img[smilieid]{max-height:22px;margin:1px;vertical-align:top;}
- .comiis_messages {
- font-size: 16px !important;
- line-height: 1.6 !important;
- }
- .comiis_a {
- font-size: 16px !important;
- line-height: 1.6 !important;
- }
- .comiis_postli {
- font-size: 16px !important;
- }
- </style>
- <link rel="stylesheet" href="https://cdn.binmt.cc/template/comiis_app/comiis/css/comiis.css">
- <link rel="stylesheet" href="https://bbs.binmt.cc/source/plugin/comiis_app/cache/comiis_1_style.css">
- <div class="comiis_postli"><div class="comiis_messages"><div class="comiis_a">${html}</div></div></div>`;
- if (replyHref) {
- const btn = document.createElement('span');
- btn.textContent = '回复';
- btn.style.cssText = 'float:right;color:#53bcf5;margin-right:20px;cursor:pointer';
- btn.onclick = e => {
- e.stopPropagation();
- createReplyDialog(replyHref, tid, pid);
- };
- li.querySelector('h2')?.appendChild(btn);
- }
- }
- }
- function initPostReply() {
- const cfg = PREVIEW_CONFIG.postReply;
- initCommonListObserver(cfg.threadSelector, `${cfg.threadSelector}>li`,
- li => !li.hasAttribute(PREVIEW_CONFIG.PROCESSED_MARK) && li.querySelector(cfg.validCheck),
- li => { createCheckReplyButton(li); });
- function createCheckReplyButton(li) {
- li.setAttribute(PREVIEW_CONFIG.PROCESSED_MARK, 'true');
- const btn = document.createElement('span');
- btn.textContent = '查看回复';
- btn.style.cssText = `
- display: block;
- width: 100%;
- text-align: center;
- padding: 6px 0;
- color:#53bcf5;
- background: #f7f8fa;
- border-radius: 4px;
- font-size: 14px;
- `;
- btn.onclick = async () => {
- if (li.dataset[cfg.loadedMark]) return;
- li.dataset[cfg.loadedMark] = "true";
- li.dataset.replyLoaded = '';
- btn.textContent = '加载中...';
- li.querySelectorAll('div[id^="pid"]').forEach(el => el.remove());
- try {
- const threadA = li.querySelector(cfg.threadASelector);
- if (!threadA) throw new Error('获取帖子信息失败');
- const tid = threadA.href.match(/thread-(\d+)-/)?.[1];
- const authorid = searchParams.get('uid') || window.discuz_uid;
- if (!tid || !authorid) throw new Error('tid/uid 获取失败');
- const apiUrl = `https://bbs.binmt.cc/forum.php?mod=viewthread&tid=${tid}&page=1&authorid=${authorid}&inajax=1`;
- const rootHtml = await fetchReplyRoot(apiUrl);
- const pidElements = parseAllPidElements(rootHtml);
- if (pidElements.length) {
- pidElements.forEach(el => li.appendChild(el));
- btn.textContent = `刷新回复 (${pidElements.length}条)`;
- } else {
- btn.textContent = '无回复';
- }
- } catch (err) {
- btn.textContent = '重试';
- console.warn('加载异常', err);
- } finally {
- li.dataset[cfg.loadedMark] = "";
- }
- };
- li.appendChild(btn);
- }
- function parseAllPidElements(rootHtml) {
- if (!rootHtml) throw new Error('获取回复数据失败');
- const div = document.createElement('div');
- div.innerHTML = rootHtml;
- return Array.from(div.querySelectorAll('div[id^="pid"]'));
- }
- }
- // ==================== 自动下一页功能 ====================
-
- const PAGINATION_ENUM = {
- noticeSelector: '.comiis_notice_list>ul',
- postListSelector: '.comiis_forumlist>ul',
- unknownPage: 999,
- loadThreshold: 1000,
- requestTimeout: 3000,
- }
- let paginationState = {
- currentPage: 1,
- totalPage: 999,
- isLoading: false,
- isFailed: false,
- observedMarkers: new Set(),
- mode: '',
- listSelector: ''
- };
- function initAutoNextPage() {
- // 判断页面类型
- const url = new URL(window.location.href);
-
- if (url.searchParams.get('mod') === 'space' && url.searchParams.get('do') === 'notice') {
- paginationState.mode = 'notice';
- paginationState.listSelector = PAGINATION_ENUM.noticeSelector;
- } else if (url.searchParams.get('type') === 'reply') {
- paginationState.mode = 'postReply';
- paginationState.listSelector = PAGINATION_ENUM.postListSelector;
- } else {
- console.log('自动下一页:当前页面不支持分页功能');
- return;
- }
- // 检查是否有分页元素
- if (!$('.comiis_page').length) {
- console.log('自动下一页:无分页元素,功能终止');
- return;
- }
- // 获取分页信息
- const pageInfos = getPaginationPageInfo();
- paginationState.currentPage = pageInfos.currentPage;
- paginationState.totalPage = pageInfos.totalPage;
- console.log(`自动下一页:初始化分页功能,第${paginationState.currentPage}/${paginationState.totalPage}页`);
- // 初始化分页功能
- initPagination();
- }
- function getPaginationPageInfo() {
- const $select = $('#dumppage');
- const totalPage = $select.length ? $select.find('option').length : PAGINATION_ENUM.unknownPage;
- const urlPage = new URL(window.location.href).searchParams.get('page');
- let currentPage = parseInt(urlPage?.trim()) || ($select.length ? parseInt($select.find('option:selected').val()) : 1);
-
- if (currentPage < 1) currentPage = 1;
- else if (!Number.isInteger(currentPage)) currentPage = Math.floor(currentPage);
-
- return { currentPage, totalPage };
- }
- function initPagination() {
- // 隐藏原始分页选择器
- $('.comiis_page').css('display', 'none');
- // 添加当前页标记
- addPageMarker({ pageNum: paginationState.currentPage });
-
- // 启动滚动监听
- $(window).scroll(handleScroll);
- console.log('自动下一页:滚动加载监听已启动');
- // 延迟检查是否需要自动加载
- setTimeout(() => {
- checkAndLoadNext();
- }, 500);
- // 绑定页码跳转事件
- $(document).off('click', '.page-jump-link').on('click', '.page-jump-link', function () {
- const inputPage = prompt(`请输入要跳转的页码(1-${paginationState.totalPage}):`, paginationState.currentPage);
- if (!inputPage) return;
- const targetPage = parseInt(inputPage.trim());
- if (isNaN(targetPage) || targetPage < 1 || targetPage > paginationState.totalPage) {
- alert(`请输入1-${paginationState.totalPage}之间的有效数字!`);
- return;
- }
- window.location.href = buildJumpUrl(targetPage);
- });
- }
- // 智能加载检测:如果内容不足一页,自动加载下一页
- function checkAndLoadNext() {
- if (paginationState.isFailed || paginationState.isLoading || paginationState.currentPage >= paginationState.totalPage) {
- return;
- }
- const $postList = $(paginationState.listSelector).first();
- if (!$postList.length) return;
- // 检查是否还有未加载的标记(表示还有下一页)
- const hasMorePages = paginationState.currentPage < paginationState.totalPage;
- if (!hasMorePages) return;
- // 检查当前显示的内容是否不足一页
- const listHeight = $postList.height();
- const windowHeight = $(window).height();
-
- // 如果列表高度小于窗口高度,说明内容不足一页,无法通过滚动触发
- if (listHeight < windowHeight) {
- console.log('自动下一页:内容不足一页,自动加载下一页');
- loadPage(paginationState.currentPage + 1);
- }
- }
- function addPageMarker({ pageNum = paginationState.currentPage, isLoadingState, errorObject, loadAll }) {
- const $postList = $(paginationState.listSelector).first();
- if (!$postList.length || (paginationState.currentPage == 1 && pageNum == 1)) return;
- // 移除加载中标记
- $postList.find(`li:contains("加载中...")`).remove();
- const totalPageText = paginationState.totalPage != PAGINATION_ENUM.unknownPage ? `/共${paginationState.totalPage}页` : '';
- let prepend = pageNum <= paginationState.currentPage;
- let marker = null;
- if (isLoadingState) {
- marker = $(`<li style="text-align:center; padding: 0; margin:10px 0;"> <span class="page-jump-link" style="color:#507daf;">第${pageNum}页</span>
- ${totalPageText} 加载中...</li>`)
- } else if (errorObject) {
- marker = $(`<li class="retry-marker" style="text-align:center; padding: 0; margin:10px 0; color:red;">
- <span class="page-jump-link" style="color:#507daf;">第${pageNum}页</span>${totalPageText} 加载失败
- <span class="retry-button" style="color:#007bff; margin-left:5px;">点击重试</span>
- <p style="color:red; margin-left:5px;"></p>
- </li>`)
- const errorMessage = typeof (errorObject == 'string') ? errorObject : JSON.stringify(errorObject);
- const truncatedErrorMessage = errorMessage.length > 200 ? `${errorMessage.substring(0, 200)}......` : errorMessage;
- marker.find('p').text(truncatedErrorMessage);
- $(marker).on('click', '.retry-button', function () {
- paginationState.isFailed = false;
- loadPage(pageNum);
- $(this).closest('.retry-marker').remove();
- });
- } else if (loadAll) {
- marker = $(`<li style="text-align:center; padding: 0; margin:10px 0; color:#666;">
- 已全部 <span class="page-jump-link" style="color:#507daf;">共${pageNum}页</span>
- 加载 <a href="${buildJumpUrl(1)}" style="color:#507daf;">回到第1页</a>
- </li>`)
- prepend = false;
- } else {
- marker = $(`<li style="text-align:center; padding: 0; margin:10px 0;">
- <span class="page-jump-link" style="color:#507daf;">第${pageNum}页</span>${totalPageText}
- ${(prepend && pageNum != 1) ? `<span class="loadPreNext" style="color:#507daf;">上一页</span>` : ''}
- </li>`)
- $(marker).on('click', '.loadPreNext', function () {
- if (paginationState.isFailed) {
- alert('下一页加载发生错误,重试后才允许加载上一页。');
- return;
- }
- loadPage(pageNum - 1);
- $(this).remove();
- });
- }
- if (prepend) {
- $postList.prepend(marker);
- } else {
- $postList.append(marker);
- }
- }
- function buildJumpUrl(targetPage, inajax) {
- const url = new URL(window.location.href);
- url.searchParams.set('page', targetPage);
- if (inajax) {
- url.searchParams.set('inajax', '1');
- } else {
- url.searchParams.delete('inajax');
- }
- return url.toString();
- }
- function loadPage(page) {
- if (paginationState.isLoading || (page > paginationState.totalPage || page < 1) || paginationState.isFailed) return;
- addPageMarker({ pageNum: page, isLoadingState: true });
- const requestUrl = buildJumpUrl(page, true);
- paginationState.isLoading = true;
- $.ajax({
- type: 'GET',
- url: requestUrl,
- dataType: 'xml',
- timeout: PAGINATION_ENUM.requestTimeout
- }).then(function (response) {
- try {
- const root = response.lastChild.firstChild.nodeValue
- if (typeof (root) == "undefined" || root == null) throw new Error('数据格式错误!');
- const htmlContent = parseResponse(root);
- const $postList = $(paginationState.listSelector).first();
- if (root.includes('本版块或指定的范围内尚无主题') || (!htmlContent && paginationState.totalPage == PAGINATION_ENUM.unknownPage)) {
- allLoaded(paginationState.currentPage)
- return;
- } else if (!htmlContent) throw new Error('数据解析失败!')
- if (page < paginationState.currentPage) {
- $postList.prepend(htmlContent);
- addPageMarker({ pageNum: page });
- } else {
- addPageMarker({ pageNum: page });
- $postList.append(htmlContent);
- paginationState.currentPage = page;
- }
- console.log(`自动下一页:加载成功第${paginationState.currentPage}/${paginationState.totalPage}页`);
- // 初始化新增元素的功能按钮
- window.comiis_recommend_addkey?.();
- window.comiis_user_gz_key?.();
- if (window.popup?.init) window.popup.init();
- // 加载完成后检查是否需要继续自动加载
- setTimeout(() => {
- checkAndLoadNext();
- }, 500);
- if (page >= paginationState.totalPage || (!root.includes('下一页') && paginationState.totalPage == PAGINATION_ENUM.unknownPage)) {
- allLoaded(page);
- }
- } catch (error) {
- return $.Deferred().reject(error);
- }
- }).then(null, function (e) {
- console.error(`自动下一页:加载失败第${page}页`, e);
- addPageMarker({ pageNum: page, errorObject: e });
- paginationState.isFailed = true;
- }).always(function () {
- paginationState.isLoading = false;
- });
- }
- function parseResponse(root) {
- const $temp = $(`<div>${root}</div>`);
- return $temp.find(paginationState.listSelector).html() || '';
- }
- function handleScroll() {
- if (paginationState.isFailed || paginationState.isLoading || paginationState.currentPage >= paginationState.totalPage) return;
- const scrollTop = $(window).scrollTop();
- const windowHeight = $(window).height();
- const docHeight = $(document).height();
- if (docHeight - (scrollTop + windowHeight) <= PAGINATION_ENUM.loadThreshold) {
- loadPage(paginationState.currentPage + 1);
- }
- }
- function allLoaded(pageNum = paginationState.totalPage) {
- addPageMarker({ pageNum, loadAll: true });
- $(window).off("scroll", handleScroll);
- console.log("自动下一页:所有页已全部加载,解除滚动监听。");
- }
- // ==================== 页面类型判断和功能启动 ====================
-
- let pageType = '未知页面'
- // 判断页面类型并启动相应功能
- if (phpFile === 'home.php' && searchParams.get('mod') === 'space' && searchParams.get('do') === 'notice') {
- // 消息提醒页面 - 启动消息预览和自动下一页功能
- await initNoticePreview();
- pageType = '【消息提醒页】'
-
- // 启动自动下一页功能
- initAutoNextPage();
- } else if (phpFile === 'home.php' && searchParams.get('type') === 'reply') {
- // 帖子回复页面 - 启动帖子回复查看和自动下一页功能
- initPostReply();
- pageType = '【帖子回复页】'
-
- // 启动自动下一页功能
- initAutoNextPage();
- }
- console.log('当前页面类型:', pageType);
- })();
复制代码 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|