Greasy Fork

Greasy Fork is available in English.

Bilibili 禁止新标签页打开链接

让哔哩哔哩所有链接在当前标签页打开

目前为 2025-02-16 提交的版本。查看 最新版本

// ==UserScript==
// @name         Bilibili 禁止新标签页打开链接
// @name:en      Bilibili No New Tab
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  让哔哩哔哩所有链接在当前标签页打开
// @description:en Force all Bilibili links to open in the current tab instead of a new tab
// @author       ChingyuanCheng
// @license      MIT
// @match        *://*.bilibili.com/*
// @match        *://live.bilibili.com/*
// @match        *://manga.bilibili.com/*
// @match        *://bilibili.com/anime/*
// @match        *://bilibili.com/match/*
// @match        *://game.bilibili.com/*
// @match        *://game.bilibili.com/platform/*
// @match        *://space.bilibili.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // 辅助函数:确保URL为绝对路径
    function resolveUrl(url) {
        try {
            return new URL(url, window.location.href).href;
        } catch {
            return null;
        }
    }

    /**
     * 1. 拦截 window.open,强制当前页跳转
     */
    function interceptWindowOpen() {
        const originalOpen = window.open;
        window.open = function(url, target, features) {
            const resolvedUrl = resolveUrl(url);
            if (resolvedUrl) {
                console.log(`[拦截] window.open: ${resolvedUrl}`);
                window.location.href = resolvedUrl;
            } else {
                console.log('[拦截] window.open 调用被阻止(无效URL)');
            }
            return null; // 返回 null 避免依赖返回值出错
        };
    }

    /**
     * 2. 拦截点击事件,处理动态添加的 target="_blank" 链接
     */
    function preventNewTabClick() {
        document.addEventListener('click', function(event) {
            let target = event.target;
            while (target && target.tagName !== 'A') {
                target = target.parentElement;
            }
            if (target?.tagName === 'A' && target.target === '_blank') {
                event.preventDefault();
                event.stopImmediatePropagation();
                const resolvedUrl = resolveUrl(target.href);
                if (resolvedUrl) {
                    console.log(`[拦截] 动态链接点击: ${resolvedUrl}`);
                    window.location.href = resolvedUrl;
                }
            }
        }, true); // 捕获阶段处理
    }

    /**
     * 3. 移除所有静态和动态的 target="_blank" 属性
     */
    function modifyLinks() {
        document.querySelectorAll('a[target="_blank"]').forEach(a => {
            a.removeAttribute('target');
            a.rel = 'noopener noreferrer';
        });
    }

    /**
     * 4. 观察DOM变化,处理动态添加的链接
     */
    function observeDynamicContent() {
        const observer = new MutationObserver(mutations => {
            mutations.forEach(() => modifyLinks());
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }

    // 初始化所有拦截
    function init() {
        interceptWindowOpen();
        preventNewTabClick();
        modifyLinks();
        observeDynamicContent();
    }

    // 启动脚本
    init();
})();