// ==UserScript== // @name 高级自动滚动控制器 // @namespace http://tampermonkey.net/ // @version 1.5 // @description 新增显示/隐藏面板功能(快捷键Alt+R),新增最小化快捷键(Alt+M),优化面板样式,新增关闭弹窗功能 // @author yangwenren // @match *://*/* // @grant none // ==/UserScript== (function() { 'use strict'; // 全局变量 let isScrolling = false; let scrollSpeed = 5; let scrollDirection = 'down'; let bottomAction = 'jump'; let panelMinimized = false; let panelHidden = false; let isDragging = false; let dragOffsetX = 0; let dragOffsetY = 0; let scrollInterval = null; let rafId = null; const MIN_SPEED = 1; const MAX_SPEED = 40; const SAFE_MARGIN = 15; const FIXED_PANEL_HEIGHT = 330; const MINIMIZED_HEIGHT = 45; const PANEL_WIDTH = 280; const MINIMIZED_WIDTH = 200; const TOGGLE_HOTKEY = 'Alt+R'; // 显示/隐藏快捷键 const MINIMIZE_HOTKEY = 'Alt+M'; // 最小化快捷键 // 弹窗控制变量 let isClosePopupEnabled = false; let popupCheckInterval = null; const POPUP_CHECK_DELAY = 1000; let popupFlags = { login: true, // 登录弹窗标记 download: true, // 下载弹窗标记 recommend: true // 推荐内容弹窗标记 }; let popupObserver = null; // 创建控制界面 function createControlPanel() { const panel = document.createElement('div'); panel.id = 'scrollControlPanel'; panel.style.cssText = ` position: fixed; bottom: ${SAFE_MARGIN}px; right: ${SAFE_MARGIN}px; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.12); z-index: 999999; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; width: ${PANEL_WIDTH}px; height: ${FIXED_PANEL_HEIGHT}px; user-select: none; will-change: transform, width, opacity; touch-action: none; transform: translateZ(0); transition: width 0.2s ease, box-shadow 0.2s ease, opacity 0.3s ease, padding-right 0.2s ease; overflow: hidden; padding-right: 0; `; // 标题栏 const titleBar = document.createElement('div'); titleBar.style.cssText = ` padding: 10px 18px; display: flex; justify-content: space-between; align-items: center; cursor: move; border-top-left-radius: 12px; border-top-right-radius: 12px; transition: background-color 0.2s ease; height: 45px; box-sizing: border-box; `; titleBar.classList.add('drag-handle'); titleBar.addEventListener('mousedown', () => { titleBar.style.opacity = '0.9'; }); titleBar.addEventListener('mouseup', () => { titleBar.style.opacity = '1'; }); const title = document.createElement('h3'); title.textContent = '高级滚动控制器'; title.style.cssText = 'margin: 0; font-size: 15px; font-weight: 500; letter-spacing: 0.3px; transition: font-size 0.2s ease;'; // 按钮容器 const buttonContainer = document.createElement('div'); buttonContainer.style.display = 'flex'; buttonContainer.style.gap = '6px'; // 最小化按钮 const minBtn = document.createElement('button'); minBtn.textContent = '−'; minBtn.title = `最小化面板(快捷键:${MINIMIZE_HOTKEY})`; minBtn.style.cssText = ` width: 26px; height: 26px; border: none; background: transparent; font-size: 20px; cursor: pointer; line-height: 1; padding: 0; border-radius: 50%; transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; `; minBtn.addEventListener('mouseover', () => { minBtn.style.backgroundColor = 'rgba(0,0,0,0.08)'; }); minBtn.addEventListener('mouseout', () => { minBtn.style.backgroundColor = 'transparent'; }); minBtn.addEventListener('click', () => toggleMinimize(panel)); // 隐藏面板按钮 const hideBtn = document.createElement('button'); hideBtn.textContent = '⇨'; hideBtn.title = `隐藏面板(快捷键:${TOGGLE_HOTKEY})`; hideBtn.style.cssText = ` width: 26px; height: 26px; border: none; background: transparent; font-size: 16px; cursor: pointer; line-height: 1; padding: 0; border-radius: 50%; transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; `; hideBtn.addEventListener('mouseover', () => { hideBtn.style.backgroundColor = 'rgba(0,0,0,0.08)'; }); hideBtn.addEventListener('mouseout', () => { hideBtn.style.backgroundColor = 'transparent'; }); hideBtn.addEventListener('click', () => togglePanelVisibility(panel)); buttonContainer.append(minBtn, hideBtn); titleBar.append(title, buttonContainer); panel.appendChild(titleBar); // 内容区域 const contentArea = document.createElement('div'); contentArea.id = 'panelContent'; contentArea.style.cssText = ` padding: 18px; transition: display 0.2s ease; height: calc(${FIXED_PANEL_HEIGHT}px - 45px); box-sizing: border-box; overflow: hidden; `; // 速度控制 const speedDiv = document.createElement('div'); speedDiv.style.cssText = ` margin-bottom: 15px; display: flex; flex-direction: column; gap: 6px; `; const speedLabel = document.createElement('label'); speedLabel.textContent = `滚动速度: ${scrollSpeed}`; speedLabel.id = 'speedLabel'; speedLabel.style.cssText = ` display: block; font-size: 14px; font-weight: 400; `; const speedSlider = document.createElement('input'); speedSlider.type = 'range'; speedSlider.min = MIN_SPEED; speedSlider.max = MAX_SPEED; speedSlider.value = scrollSpeed; speedSlider.style.cssText = ` width: 100%; height: 6px; -webkit-appearance: none; appearance: none; border-radius: 3px; outline: none; `; speedSlider.style.setProperty('-webkit-slider-thumb', ` -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%; background: #4CAF50; cursor: pointer; transition: all 0.2s ease; `); speedSlider.addEventListener('input', function() { scrollSpeed = parseInt(this.value); document.getElementById('speedLabel').textContent = `滚动速度: ${scrollSpeed}`; if (isScrolling) updateScrollInterval(); }); speedDiv.append(speedLabel, speedSlider); contentArea.appendChild(speedDiv); // 方向控制 const directionDiv = document.createElement('div'); directionDiv.style.cssText = ` margin-bottom: 15px; display: flex; align-items: center; gap: 12px; `; const directionLabel = document.createElement('label'); directionLabel.textContent = '滚动方向:'; directionLabel.style.cssText = ` width: 85px; font-size: 14px; font-weight: 400; `; const directionSelect = document.createElement('select'); directionSelect.style.cssText = ` flex: 1; padding: 7px 12px; border-radius: 6px; border: 1px solid; font-size: 14px; background-color: transparent; cursor: pointer; transition: all 0.2s ease; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; background-size: 14px; padding-right: 35px; `; directionSelect.addEventListener('mouseover', () => { directionSelect.style.borderColor = 'rgba(0,0,0,0.2)'; }); directionSelect.addEventListener('mouseout', () => { updateTheme(); }); directionSelect.innerHTML = ` `; directionSelect.value = scrollDirection; directionSelect.addEventListener('change', function() { scrollDirection = this.value; if (isScrolling) updateScrollInterval(); }); directionDiv.append(directionLabel, directionSelect); contentArea.appendChild(directionDiv); // 底部行为控制 const actionDiv = document.createElement('div'); actionDiv.style.cssText = ` margin-bottom: 15px; display: flex; align-items: center; gap: 12px; `; const actionLabel = document.createElement('label'); actionLabel.textContent = '底部行为:'; actionLabel.style.cssText = ` width: 85px; font-size: 14px; font-weight: 400; `; const actionSelect = document.createElement('select'); actionSelect.style.cssText = ` flex: 1; padding: 7px 12px; border-radius: 6px; border: 1px solid; font-size: 14px; background-color: transparent; cursor: pointer; transition: all 0.2s ease; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; background-size: 14px; padding-right: 35px; `; actionSelect.addEventListener('mouseover', () => { actionSelect.style.borderColor = 'rgba(0,0,0,0.2)'; }); actionSelect.addEventListener('mouseout', () => { updateTheme(); }); actionSelect.innerHTML = ` `; actionSelect.value = bottomAction; actionSelect.addEventListener('change', function() { bottomAction = this.value; if (isScrolling) updateScrollInterval(); }); actionDiv.append(actionLabel, actionSelect); contentArea.appendChild(actionDiv); // 自动关闭弹窗控制项 const popupControlDiv = document.createElement('div'); popupControlDiv.style.cssText = ` margin-bottom: 10px; display: flex; align-items: center; gap: 12px; `; const popupLabel = document.createElement('label'); popupLabel.textContent = '自动关闭弹窗:'; popupLabel.style.cssText = ` width: 100px; font-size: 14px; font-weight: 400; `; const popupToggle = document.createElement('input'); popupToggle.type = 'checkbox'; popupToggle.id = 'popupCloseToggle'; popupToggle.style.cssText = ` width: 18px; height: 18px; cursor: pointer; accent-color: #4CAF50; `; popupToggle.checked = isClosePopupEnabled; popupToggle.addEventListener('change', function() { isClosePopupEnabled = this.checked; if (isClosePopupEnabled) { startPopupHandling(); } else { stopPopupHandling(); } }); popupControlDiv.append(popupLabel, popupToggle); contentArea.appendChild(popupControlDiv); // 弹窗类型过滤 const popupFilterDiv = document.createElement('div'); popupFilterDiv.style.cssText = ` margin-bottom: 15px; display: flex; flex-wrap: wrap; gap: 8px; font-size: 13px; `; const createFilterCheckbox = (type, label) => { const container = document.createElement('div'); container.style.display = 'flex'; container.style.alignItems = 'center'; container.style.gap = '4px'; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.id = `filter-${type}`; checkbox.checked = popupFlags[type]; checkbox.style.width = '12px'; checkbox.style.height = '14px'; checkbox.addEventListener('change', () => { popupFlags[type] = checkbox.checked; }); const lbl = document.createElement('label'); lbl.htmlFor = `filter-${type}`; lbl.textContent = label; lbl.style.cursor = 'pointer'; container.append(checkbox, lbl); return container; }; popupFilterDiv.append( createFilterCheckbox('login', '登录弹窗'), createFilterCheckbox('download', '下载弹窗'), createFilterCheckbox('recommend', '推荐弹窗') ); contentArea.appendChild(popupFilterDiv); // 控制按钮 const buttonDiv = document.createElement('div'); buttonDiv.style.cssText = ` display: flex; gap: 10px; `; const startBtn = document.createElement('button'); startBtn.id = 'startScrollBtn'; startBtn.textContent = '开始滚动'; startBtn.style.cssText = ` flex: 1; padding: 8px 12px; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 5px rgba(0,0,0,0.1); `; startBtn.addEventListener('mouseover', () => { startBtn.style.transform = 'translateY(-1px)'; startBtn.style.boxShadow = '0 4px 8px rgba(0,0,0,0.15)'; }); startBtn.addEventListener('mouseout', () => { startBtn.style.transform = 'translateY(0)'; startBtn.style.boxShadow = '0 2px 5px rgba(0,0,0,0.1)'; }); const stopBtn = document.createElement('button'); stopBtn.id = 'stopScrollBtn'; stopBtn.textContent = '停止滚动'; stopBtn.style.cssText = ` flex: 1; padding: 8px 12px; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 5px rgba(0,0,0,0.1); opacity: 0.7; `; stopBtn.disabled = true; stopBtn.addEventListener('mouseover', () => { if (!stopBtn.disabled) { stopBtn.style.transform = 'translateY(-1px)'; stopBtn.style.boxShadow = '0 4px 8px rgba(0,0,0,0.15)'; } }); stopBtn.addEventListener('mouseout', () => { if (!stopBtn.disabled) { stopBtn.style.transform = 'translateY(0)'; stopBtn.style.boxShadow = '0 2px 5px rgba(0,0,0,0.1)'; } }); startBtn.addEventListener('click', () => { if (!isScrolling) { startScrolling(); isScrolling = true; startBtn.disabled = true; stopBtn.disabled = false; stopBtn.style.opacity = '1'; } }); stopBtn.addEventListener('click', () => { stopScrolling(); isScrolling = false; startBtn.disabled = false; stopBtn.disabled = true; stopBtn.style.opacity = '0.7'; }); buttonDiv.append(startBtn, stopBtn); contentArea.appendChild(buttonDiv); panel.appendChild(contentArea); document.body.appendChild(panel); // 初始化主题 updateTheme(); window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateTheme); // 初始化拖动 initDragEvents(panel, titleBar); // 窗口大小变化监听 window.addEventListener('resize', () => { if (!panelHidden) checkBounds(panel); }); // 初始化快捷键 initHotkeys(panel); return panel; } // 切换面板显示/隐藏状态 function togglePanelVisibility(panel) { panelHidden = !panelHidden; if (panelHidden) { panel.style.opacity = '0'; panel.style.pointerEvents = 'none'; const hideBtn = panel.querySelector('button:last-of-type'); if (hideBtn) hideBtn.textContent = '⇦'; } else { panel.style.opacity = '1'; panel.style.pointerEvents = 'auto'; const hideBtn = panel.querySelector('button:last-of-type'); if (hideBtn) hideBtn.textContent = '⇨'; checkBounds(panel); } } // 切换最小化状态 function toggleMinimize(panel) { if (panelHidden) return; const content = document.getElementById('panelContent'); const minBtn = panel.querySelector('button:first-of-type'); const title = panel.querySelector('h3'); const buttonContainer = panel.querySelector('.drag-handle > div'); panelMinimized = !panelMinimized; if (panelMinimized) { content.style.display = 'none'; panel.style.width = `${MINIMIZED_WIDTH}px`; panel.style.height = `${MINIMIZED_HEIGHT}px`; panel.style.paddingRight = '0'; minBtn.textContent = '+'; title.style.fontSize = '15px'; buttonContainer.style.gap = '1px'; } else { content.style.display = 'block'; panel.style.width = `${PANEL_WIDTH}px`; panel.style.height = `${FIXED_PANEL_HEIGHT}px`; panel.style.paddingRight = '0'; minBtn.textContent = '−'; title.style.fontSize = '15px'; buttonContainer.style.gap = '6px'; } checkBounds(panel); } // 初始化所有快捷键 function initHotkeys(panel) { document.addEventListener('keydown', (e) => { // 显示/隐藏面板:Alt+R if (e.altKey && e.key.toLowerCase() === 'r') { e.preventDefault(); togglePanelVisibility(panel); } // 最小化/展开面板:Alt+M if (e.altKey && e.key.toLowerCase() === 'm') { e.preventDefault(); toggleMinimize(panel); } }); console.log(`高级滚动控制器快捷键:`); console.log(`- ${TOGGLE_HOTKEY}:显示/隐藏面板`); console.log(`- ${MINIMIZE_HOTKEY}:最小化/展开面板`); } // 检查面板位置 function checkBounds(panel) { const panelHeight = panelMinimized ? MINIMIZED_HEIGHT : FIXED_PANEL_HEIGHT; const panelWidth = panelMinimized ? MINIMIZED_WIDTH : PANEL_WIDTH; const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const rect = panel.getBoundingClientRect(); let newLeft = rect.left; let newTop = rect.top; if (newLeft < SAFE_MARGIN) newLeft = SAFE_MARGIN; else if (newLeft + panelWidth > viewportWidth - SAFE_MARGIN) { newLeft = viewportWidth - panelWidth - SAFE_MARGIN; } if (newTop < SAFE_MARGIN) newTop = SAFE_MARGIN; else if (newTop + panelHeight > viewportHeight - SAFE_MARGIN) { newTop = viewportHeight - panelHeight - SAFE_MARGIN; } if (newLeft !== rect.left || newTop !== rect.top) { panel.style.left = `${newLeft}px`; panel.style.top = `${newTop}px`; panel.style.right = 'auto'; panel.style.bottom = 'auto'; panel.style.transform = 'translateZ(0)'; } } // 拖动事件 function initDragEvents(panel, handle) { let panelInitialRect; handle.addEventListener('mousedown', (e) => { if (panelHidden) return; e.preventDefault(); e.stopPropagation(); isDragging = true; panelInitialRect = panel.getBoundingClientRect(); dragOffsetX = e.clientX - panelInitialRect.left; dragOffsetY = e.clientY - panelInitialRect.top; document.body.style.cursor = 'grabbing'; handle.style.cursor = 'grabbing'; document.body.style.userSelect = 'none'; panel.style.boxShadow = '0 6px 25px rgba(0,0,0,0.15)'; }); document.addEventListener('mousemove', (e) => { if (!isDragging || panelHidden) return; e.preventDefault(); if (rafId) cancelAnimationFrame(rafId); rafId = requestAnimationFrame(() => { const newLeft = e.clientX - dragOffsetX; const newTop = e.clientY - dragOffsetY; panel.style.transform = `translate( ${newLeft - panelInitialRect.left}px, ${newTop - panelInitialRect.top}px ) translateZ(0)`; }); }); function endDrag() { if (isDragging) { isDragging = false; cancelAnimationFrame(rafId); rafId = null; document.body.style.cursor = ''; handle.style.cursor = 'move'; document.body.style.userSelect = ''; panel.style.boxShadow = '0 4px 20px rgba(0,0,0,0.12)'; const rect = panel.getBoundingClientRect(); panel.style.left = `${rect.left}px`; panel.style.top = `${rect.top}px`; panel.style.transform = 'translateZ(0)'; checkBounds(panel); } } document.addEventListener('mouseup', endDrag); document.addEventListener('mouseleave', endDrag); } // 停止滚动函数 function stopScrolling() { if (isScrolling && scrollInterval) { clearInterval(scrollInterval); scrollInterval = null; } isScrolling = false; const startBtn = document.getElementById('startScrollBtn'); const stopBtn = document.getElementById('stopScrollBtn'); if (startBtn) startBtn.disabled = false; if (stopBtn) { stopBtn.disabled = true; stopBtn.style.opacity = '0.7'; } } // 主题更新函数 function updateTheme() { const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; const panel = document.getElementById('scrollControlPanel'); if (!panel) return; const titleBar = panel.querySelector('.drag-handle'); const title = panel.querySelector('h3'); const buttons = panel.querySelectorAll('.drag-handle button'); const labels = panel.querySelectorAll('label'); const selects = panel.querySelectorAll('select'); const startBtn = document.getElementById('startScrollBtn'); const stopBtn = document.getElementById('stopScrollBtn'); const speedSlider = panel.querySelector('input[type="range"]'); if (isDarkMode) { panel.style.backgroundColor = 'rgba(28, 28, 30, 0.98)'; panel.style.border = '1px solid rgba(70, 70, 75, 0.5)'; titleBar.style.backgroundColor = 'rgba(44, 44, 46, 0.9)'; title.style.color = '#f5f5f7'; buttons.forEach(btn => btn.style.color = '#d2d2d7'); labels.forEach(label => label.style.color = '#e4e4e7'); selects.forEach(select => { select.style.backgroundColor = 'rgba(44, 44, 46, 0.8)'; select.style.color = '#e4e4e7'; select.style.borderColor = 'rgba(70, 70, 75, 0.8)'; }); speedSlider.style.backgroundColor = 'rgba(70, 70, 75, 0.5)'; speedSlider.style.setProperty('-webkit-slider-thumb', ` -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%; background: #4CAF50; cursor: pointer; transition: all 0.2s ease; `); if (startBtn) startBtn.style.backgroundColor = '#43a047'; if (stopBtn) stopBtn.style.backgroundColor = '#e53935'; } else { panel.style.backgroundColor = 'rgba(255, 255, 255, 0.98)'; panel.style.border = '1px solid rgba(220, 220, 225, 0.8)'; titleBar.style.backgroundColor = 'rgba(249, 249, 250, 0.9)'; title.style.color = '#1d1d1f'; buttons.forEach(btn => btn.style.color = '#6e6e73'); labels.forEach(label => label.style.color = '#1d1d1f'); selects.forEach(select => { select.style.backgroundColor = 'rgba(249, 249, 250, 0.8)'; select.style.color = '#1d1d1f'; select.style.borderColor = 'rgba(220, 220, 225, 0.8)'; }); speedSlider.style.backgroundColor = 'rgba(220, 220, 225, 0.8)'; speedSlider.style.setProperty('-webkit-slider-thumb', ` -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%; background: #4CAF50; cursor: pointer; transition: all 0.2s ease; `); if (startBtn) startBtn.style.backgroundColor = '#4CAF50'; if (stopBtn) stopBtn.style.backgroundColor = '#f44336'; } } // 更新滚动间隔 function updateScrollInterval() { if (scrollInterval) { clearInterval(scrollInterval); scrollInterval = null; } startScrolling(); } // 滚动逻辑实现 function startScrolling() { if (scrollInterval) return; scrollInterval = setInterval(() => { const currentPos = window.scrollY; const windowHeight = window.innerHeight; const docHeight = Math.max( document.body.scrollHeight, document.body.offsetHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight ); const atBottom = currentPos + windowHeight >= docHeight - 50; const atTop = currentPos <= 50; let newPos = currentPos; if (scrollDirection === 'down') { newPos = currentPos + scrollSpeed; if (atBottom) { switch (bottomAction) { case 'jump': newPos = 0; break; case 'reverse': scrollDirection = 'up'; newPos = currentPos - scrollSpeed; break; case 'stop': stopScrolling(); return; } } } else { newPos = currentPos - scrollSpeed; if (atTop) { switch (bottomAction) { case 'jump': newPos = docHeight - windowHeight; break; case 'reverse': scrollDirection = 'down'; newPos = currentPos + scrollSpeed; break; case 'stop': stopScrolling(); return; } } } window.scrollTo(0, newPos); }, 20); } // 弹窗选择器集合,覆盖更多场景 const popupSelectors = { login: [ ".passport-login-container", ".signFlowModal", ".login-popover", ".modal-dialog-centered", ".loginBenefitNotification", ".lt-row", ".login-panel-popover:has(.login-tip-content)", ".bpx-player-toast-wrap", "div:has(.unlogin-popover-avatar)", ".vW4dJNzI", "#related-video-card-login-guide", ".HDhMLx9a", ".modal__login", ".sideUnlogin", ".ReactModal__Overlay--after-open:not(.ReactModal__Overlay_content-page)" ], download: [ ".weixin-shadowbox", ".download-app-guidance", ".app-open-drawer", ".at-app-banner", ".callEnd_box", ".m-iqyGuide-layer", ".m-open-app.fixed-openapp", ".m-space-float-openapp", ".mplayer-widescreen-callapp", ".m-float-openapp", ".openapp-dialog", ".xigua-download", ".album-btn-container", ".btn-open", ".downloadButton", ".app-fixed-btn", ".app-download__wrapper", ".FloatDownloadButton_mobile_xiaoxue-button_1jZ", ".index_xiaoxue-button_1Av", ".widget__download-app", ".app-opener" ], recommend: [ ".recommend-box", ".add-panel", "#dftt-message-wrapper", ".trial-feed-wrap", ".feed-Sign-weixin", ".feed-Sign-span", ".call-app-btn", ".index_call-app-btn", ".open-button", ".bottom-login-guide", "#J-invoke-baiduApp-float", ".nav-bar-bottom", ".wk-student-defense", ".wk-student-limit-jump", ".bartop", ".wk-bottom-btn", "#bdrainrwDragButton", ".drag-bottom", ".slider-top-bar_sliderWrapper__1Nize", ".bottom-bar_buttonWrap__NXBe-", "#opeApp", ".undefined", ".Corner-container", ".open-app-top", ".top-video-card-img-app", ".video-player-download-tips", ".open-app-bottom", ".NewOpenApp", ".player-lefttip-inner", "#passport-login-pop", ".pop-mask", ".page-top-rightinfo-popover", "#popupModule", ".open-link", "[srcid=xcx_multi]", "[srcid=app_mobile_simple]", "[srcid=app_mobile_simple_safety]", "[srcid=app_mobile_ios]" ] }; // 关闭按钮选择器集合 const closeButtonSelectors = [ ".close", ".Modal-closeButton", ".bili-mini-close-icon", ".DKE9HSAk", "img[alt='关闭']", "[class*='close']", "[class*='Close']", ".icon-btn-wrapper", ".ant-modal-close", "button:contains('关闭')", "button:contains('取消')", "span:contains('×')", "button:contains('×')" ]; // 通过内容(xpath)获取节点 function getXpath(xpath, parent) { try { let xpathResult = document.evaluate(xpath, parent || document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); return xpathResult.singleNodeValue; } catch (e) { return null; } } // 安全点击函数,避免触发防点击劫持 function safeClick(button) { try { // 先触发鼠标按下事件 const mousedownEvent = new MouseEvent('mousedown', { bubbles: true, cancelable: true, view: window }); button.dispatchEvent(mousedownEvent); // 再触发点击事件 const clickEvent = new MouseEvent('click', { bubbles: true, cancelable: true, view: window }); button.dispatchEvent(clickEvent); // 最后触发鼠标释放事件 const mouseupEvent = new MouseEvent('mouseup', { bubbles: true, cancelable: true, view: window }); button.dispatchEvent(mouseupEvent); } catch (e) { console.error('点击关闭按钮失败:', e); } } // 智能查找关闭按钮 function findCloseButton(popup) { // 先尝试直接选择器查找 for (const selector of closeButtonSelectors) { try { const btn = popup.querySelector(selector); if (btn) return btn; } catch (e) { continue; } } // 再尝试通过文本查找 const textBasedButtons = [ getXpath("//button[contains(text(), '关闭')]", popup), getXpath("//a[contains(text(), '关闭')]", popup), getXpath("//span[contains(text(), '关闭')]", popup) ]; return textBasedButtons.find(btn => btn !== null); } // 处理检测到的弹窗 function handlePopup(popup, type) { // 尝试找到关闭按钮 const closeBtn = findCloseButton(popup); if (closeBtn) { safeClick(closeBtn); console.log(`自动关闭${type}弹窗`); return true; } else if (type !== 'login') { // 找不到关闭按钮时直接隐藏(登录弹窗除外) popup.style.display = 'none !important'; console.log(`直接隐藏${type}弹窗`); return true; } return false; } // 检测并关闭弹窗 function detectAndClosePopups() { // 检查所有新增节点 const allElements = document.getElementsByTagName('*'); for (let element of allElements) { // 检测各类弹窗 Object.entries(popupSelectors).forEach(([type, selectors]) => { if (!popupFlags[type]) return; selectors.some(selector => { try { if (element.matches(selector)) { return handlePopup(element, type); } const popup = element.querySelector(selector); if (popup) { return handlePopup(popup, type); } } catch (e) { return false; } return false; }); }); } } // 启动弹窗处理 function startPopupHandling() { // 停止任何已有的处理 stopPopupHandling(); // 立即执行一次检测 detectAndClosePopups(); // 设置定时检测作为备份 popupCheckInterval = setInterval(detectAndClosePopups, POPUP_CHECK_DELAY); // 创建DOM变化观察者 popupObserver = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { for (const node of mutation.addedNodes) { if (!(node instanceof HTMLElement)) continue; // 检测并处理各类弹窗 Object.entries(popupSelectors).forEach(([type, selectors]) => { if (!popupFlags[type]) return; selectors.some(selector => { try { const popup = node.querySelector(selector) || (node.matches(selector) ? node : null); if (popup) { return handlePopup(popup, type); } } catch (e) { return false; } return false; }); }); } } }); // 启动观察者 popupObserver.observe(document, { childList: true, subtree: true, attributes: false, characterData: false }); } // 停止弹窗处理 function stopPopupHandling() { if (popupCheckInterval) { clearInterval(popupCheckInterval); popupCheckInterval = null; } if (popupObserver) { popupObserver.disconnect(); popupObserver = null; } } // 初始化 if (document.readyState === 'complete' || document.readyState === 'interactive') { createControlPanel(); } else { document.addEventListener('DOMContentLoaded', createControlPanel); setTimeout(createControlPanel, 3000); } })();