fail link show

标识无效的a标签

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         fail link show
// @namespace    [email protected]
// @description  标识无效的a标签
// @version      0.3
// @match        *://*.3d66.com/*
// @grant        none
// @license MIT
// ==/UserScript==

(() => {
  "use strict";

  const STYLE_ID = "__query_only_mark_style__";
  const MARK_CLASS = "__query_only_mark";
  const BADGE_CLASS = "__query_only_badge";

  const ensureStyle = () => {
    if (document.getElementById(STYLE_ID)) return;
    const styleEl = document.createElement("style");
    styleEl.id = STYLE_ID;
    styleEl.textContent = `
      a.${MARK_CLASS}{
        outline:none !important;
      }
      a.${MARK_CLASS} .${BADGE_CLASS}{
        position:absolute !important;top:4px !important;right:4px !important;z-index:99999 !important;
        pointer-events:none !important;
        display:inline-flex !important;align-items:center !important;justify-content:center !important;
        width:16px !important;height:16px !important;
        font-size:10px !important;line-height:1 !important;border-radius:999px !important;
        font-weight:700 !important;
        color:#fff !important;
        background:linear-gradient(145deg,#ff6b6b,#d32f2f) !important;
        border:1px solid rgba(211,47,47,.9) !important;
        box-shadow:0 0 0 1px rgba(255,255,255,.9), 0 1px 4px rgba(211,47,47,.35) !important;
      }
    `;
    document.head.appendChild(styleEl);
  };

  const isEmptyHref = (href) => href == null || href.trim() === "";

  const isQueryOnlyHref = (href) => {
    if (isEmptyHref(href)) return false;
    const trimmed = href.trim();
    return trimmed.startsWith("?");
  };

  const applyBadges = () => {
    ensureStyle();
    document.querySelectorAll("a").forEach((a) => {
      const rawHref = a.getAttribute("href");
      const badge = a.querySelector(`.${BADGE_CLASS}`);
      const isBadLink = isEmptyHref(rawHref) || isQueryOnlyHref(rawHref);
      if (!isBadLink) {
        a.classList.remove(MARK_CLASS);
        badge?.remove();
        return;
      }

      const rect = a.getBoundingClientRect();
      const hasImg = a.querySelector("img") !== null;
      // 判断是否为卡片/块级元素:有图片,或尺寸较大,或绝对定位
      const computed = getComputedStyle(a);
      const isAbsolute = computed.position === "absolute" || computed.position === "fixed";
      const isCard = hasImg || (rect.height > 40 && rect.width > 40) || isAbsolute;

      // 基础样式
      const baseStyle =
        "z-index:99999;pointer-events:none;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;font-weight:700;color:#fff;background:linear-gradient(145deg,#ff6b6b,#d32f2f);border:1px solid rgba(211,47,47,.9);box-shadow:0 0 0 1px rgba(255,255,255,.9), 0 1px 4px rgba(211,47,47,.35);";

      let finalStyle = "";
      if (isCard) {
        // 卡片模式:右上角绝对定位
        if (computed.position === "static") {
          a.style.position = "relative";
        }
        finalStyle = `${baseStyle} position:absolute;top:4px;right:4px;width:16px;height:16px;font-size:10px;line-height:1;margin:0;transform:none;`;
      } else {
        // 文本模式:行内追加,不遮挡文字
        // 不需要设置 relative
        finalStyle = `${baseStyle} position:static;width:14px;height:14px;font-size:9px;line-height:1;margin-left:4px;vertical-align:middle;transform:translateY(-1px);`;
      }

      const ensureBadge = () => {
        if (!badge) {
          const nextBadge = document.createElement("span");
          nextBadge.className = BADGE_CLASS;
          nextBadge.textContent = "!";
          nextBadge.style.cssText = finalStyle;
          a.appendChild(nextBadge);
        } else {
          badge.style.cssText = finalStyle;
          // 确保在最后,防止位置不对
          if (a.lastElementChild !== badge) {
            a.appendChild(badge);
          }
        }
      };
      ensureBadge();
    });
  };

  let rafId = null;
  const scheduleApply = () => {
    if (rafId) return;
    rafId = requestAnimationFrame(() => {
      rafId = null;
      applyBadges();
    });
  };

  const observer = new MutationObserver(() => scheduleApply());
  observer.observe(document.documentElement, { subtree: true, childList: true, attributes: true });

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", () => applyBadges(), { once: true });
  } else {
    applyBadges();
  }
})();