Greasy Fork

Greasy Fork is available in English.

左键点击链接在新标签页打开

强制所有鼠标左键点击的普通链接都在新的浏览器标签页中打开。

当前为 2025-05-26 提交的版本,查看 最新版本

// ==UserScript==
// @name         左键点击链接在新标签页打开
// @name:en      Open Links in New Tab with Left Click
// @namespace    http://greasyfork.icu/users/your-username  // 建议替换为你的 GreasyFork 用户名或自定义命名空间
// @version      1.0
// @description  强制所有鼠标左键点击的普通链接都在新的浏览器标签页中打开。
// @description:en Forces all regular links clicked with the left mouse button to open in a new browser tab.
// @author       AI Assistant
// @match        *://*/*
// @grant        GM_openInTab
// @grant        window.open
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    document.addEventListener('click', function(event) {
        // 1. 检查是否为鼠标左键点击 (event.button === 0)
        //    并且没有同时按下 Ctrl, Meta (Cmd), Shift, Alt 等修饰键
        //    (因为这些组合键通常已有浏览器默认的新标签页打开行为)
        if (event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
            return;
        }

        // 2. 查找被点击的 <a> 元素
        //    用户可能点击的是 <a> 标签内部的文字、图片等子元素
        let targetElement = event.target;
        let anchorElement = null;

        // 向上遍历DOM树,最多检查5层 (通常足够了)
        for (let i = 0; i < 5 && targetElement && targetElement !== document.body; i++) {
            if (targetElement.tagName === 'A') {
                anchorElement = targetElement;
                break;
            }
            targetElement = targetElement.parentElement;
        }

        // 3. 如果找到了 <a> 元素
        if (anchorElement) {
            const href = anchorElement.href; // 使用 .href 获取完整的、经过解析的绝对URL
            const rawHref = anchorElement.getAttribute('href'); // 获取原始 href 属性值

            // 4. 过滤无效或特殊链接
            if (!href || href === '#' || (rawHref && rawHref.startsWith('#')) || href.startsWith('javascript:')) {
                // - !href: 没有 href 属性
                // - href === '#': 无效的空锚点 (现代浏览器中 .href 对 '#' 会是当前页面URL + '#')
                // - rawHref.startsWith('#'): 明确的页面内锚点链接
                // - href.startsWith('javascript:'): JavaScript 伪协议
                return;
            }

            // 5. 忽略带有 download 属性的链接 (这类链接点击后浏览器会开始下载)
            if (anchorElement.hasAttribute('download')) {
                return;
            }

            // 6. (可选) 忽略那些已经明确指定 target="_blank" (或其他非 _self 的 target) 的链接
            //    如果你希望严格覆盖所有行为,可以注释掉下面这个 if 块。
            //    但通常尊重页面自身的 target 设置会是更好的体验。
            /*
            if (anchorElement.target && anchorElement.target.toLowerCase() !== '_self') {
                return;
            }
            */

            // 7. 阻止链接的默认点击行为 (例如,在当前页面跳转)
            event.preventDefault();
            event.stopPropagation(); // 同时阻止事件冒泡,避免其他监听器干扰或重复处理

            // 8. 在新标签页打开链接
            //    优先使用 GM_openInTab (油猴脚本提供的API,通常有更好的集成和权限)
            //    如果 GM_openInTab 不可用,则回退到标准的 window.open
            if (typeof GM_openInTab === 'function') {
                GM_openInTab(href, { active: true, insert: true });
                // active: true  => 新打开的标签页会成为当前焦点
                // insert: true => (Tampermonkey 特有) 新标签页会插入到当前标签页旁边
            } else if (typeof window.open === 'function') {
                window.open(href, '_blank');
            } else {
                // 理论上不太可能两者都不可用,但作为备用提示
                console.warn('无法在新标签页中打开链接:GM_openInTab 和 window.open 均不可用。');
            }
        }
    }, true); // 使用捕获阶段监听事件,以便在链接默认行为或其他脚本处理之前捕获点击

})();