标签 弹窗自动化 下的文章

跳转到 GitHub 也要手动点击 继续 按钮,觉得太烦了,Vibe 了这个小脚本

// ==UserScript== // @name         Auto Click Popup Continue // @namespace    http://tampermonkey.net/ // @version      1.0 // @description  当弹窗中包含指定域名时,自动点击弹窗中的"继续"按钮 // @author       Your Name // @match        https://linux.do/* // @grant        none // @run-at       document-start // ==/UserScript==

(function () {
  "use strict";

  // 配置:需要检测的域名列表(支持正则表达式) const TARGET_DOMAINS = ["github.com", "github.com/", "githubusercontent.com"];

  // 标记状态 let hasClicked = false;
  let clickCooldown = false;

  // 弹窗选择器关键词 const popupSelectors = [
    '[class*="modal"]',
    '[class*="popup"]',
    '[class*="dialog"]',
    '[class*="overlay"]',
    '[class*="layer"]',
    '[role="dialog"]',
    '[role="alertdialog"]',
    ".modal",
    ".popup",
    ".dialog",
    ".overlay",
    '[aria-modal="true"]',
    ".el-dialog",
    ".ant-modal",
    ".ivu-modal",
    ".layui-layer",
    ".sweet-alert",
    ".swal-modal",
  ];

  // 检查文本是否包含目标域名 function containsTargetDomain(text) {
    if (!text) return false;

    // 支持正则表达式匹配 for (const domain of TARGET_DOMAINS) {
      try {
        // 如果是正则表达式格式 if (domain.startsWith("/") && domain.endsWith("/")) {
          const regex = new RegExp(domain.slice(1, -1));
          if (regex.test(text)) return true;
        } else {
          // 普通字符串匹配 if (text.includes(domain)) return true;
        }
      } catch (e) {
        // 正则表达式错误时回退到普通匹配 if (text.includes(domain)) return true;
      }
    }

    return false;
  }

  // 在容器中检测是否包含目标域名 function containsDomainInContainer(container) {
    // 检查所有链接 const links = container.querySelectorAll("a[href]");
    for (const link of links) {
      const href = link.getAttribute("href") || "";
      if (containsTargetDomain(href)) {
        console.log("检测到目标域名:", href);
        return true;
      }
    }

    // 检查所有文本节点 const walker = document.createTreeWalker(
      container,
      NodeFilter.SHOW_TEXT,
      null,
      false,
    );

    let node;
    while ((node = walker.nextNode())) {
      const text = node.textContent || "";
      if (containsTargetDomain(text)) {
        console.log("检测到目标域名文本:", text.substring(0, 100));
        return true;
      }
    }

    // 检查特定元素的内容 const elements = container.querySelectorAll(
      "[data-url], [href], [src], .url, .link",
    );
    for (const elem of elements) {
      const content =
        elem.getAttribute("data-url") ||
        elem.getAttribute("href") ||
        elem.getAttribute("src") ||
        elem.textContent ||
        "";

      if (containsTargetDomain(content)) {
        console.log("检测到目标域名元素:", content.substring(0, 100));
        return true;
      }
    }

    return false;
  }

  // 查找"继续"按钮 function findContinueButton(container = document) {
    const buttons = container.querySelectorAll(
      'button, input[type="button"], input[type="submit"], [role="button"], .btn, .ant-btn, .ivu-btn, .el-button',
    );

    for (const button of buttons) {
      const text = button.textContent.trim();
      const ariaLabel = button.getAttribute("aria-label") || "";
      const value = button.value || "";

      if (
        text === "继续" ||
        text.includes("继续") ||
        ariaLabel === "继续" ||
        ariaLabel.includes("继续") ||
        value === "继续" ||
        value.includes("继续")
      ) {
        if (isElementVisible(button) && !button.disabled) {
          return button;
        }
      }
    }

    return null;
  }

  // 检查元素是否可见 function isElementVisible(element) {
    if (!element) return false;

    const style = window.getComputedStyle(element);
    if (style.display === "none") return false;
    if (style.visibility === "hidden") return false;
    if (style.opacity === "0") return false;

    const rect = element.getBoundingClientRect();
    if (rect.width === 0 || rect.height === 0) return false;

    return true;
  }

  // 在弹窗中查找按钮 function findButtonInPopup() {
    const combinedSelector = popupSelectors.join(", ");
    const popups = document.querySelectorAll(combinedSelector);

    for (const popup of popups) {
      if (isElementVisible(popup)) {
        // 先检测弹窗中是否包含目标域名 if (containsDomainInContainer(popup)) {
          // 在弹窗内查找"继续"按钮 const button = findContinueButton(popup);
          if (button) {
            return button;
          }
        }
      }
    }

    // 检查页面中是否有直接包含目标域名的弹窗 const anyPopup = document.querySelector(combinedSelector);
    if (anyPopup && isElementVisible(anyPopup)) {
      if (containsDomainInContainer(anyPopup)) {
        const button = findContinueButton(anyPopup);
        if (button) {
          return button;
        }
      }
    }

    return null;
  }

  // 处理弹窗检测 function handlePopupDetection() {
    if (clickCooldown || hasClicked) return;

    const button = findButtonInPopup();

    if (button) {
      console.log('✓ 检测到包含目标域名的弹窗,自动点击"继续"按钮');
      button.click();
      hasClicked = true;
      clickCooldown = true;

      setTimeout(() => {
        clickCooldown = false;
      }, 1000);

      setTimeout(() => {
        hasClicked = false;
      }, 3000);
    }
  }

  // 创建 MutationObserver function createObserver() {
    const observer = new MutationObserver((mutations) => {
      handlePopupDetection();
    });

    observer.observe(document.body, {
      childList: true,
      subtree: true,
      attributes: true,
      attributeFilter: ["class", "style", "display"],
    });

    return observer;
  }

  // 定期检查 function startPeriodicCheck() {
    setInterval(() => {
      handlePopupDetection();
    }, 500);
  }

  // 初始化 function init() {
    createObserver();
    startPeriodicCheck();

    // 多次延迟检查
    [100, 500, 1000, 2000, 3000].forEach((delay) => {
      setTimeout(() => {
        handlePopupDetection();
      }, delay);
    });

    console.log("自动点击脚本已加载,监测域名:", TARGET_DOMAINS);
  }

  // 启动 if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }

  window.addEventListener("load", () => {
    setTimeout(() => {
      handlePopupDetection();
    }, 500);
  });
})();

📌 转载信息
原作者:
ageovb
转载时间:
2026/1/18 19:00:22