Greasy Fork is available in English.
全站通用型页内增强脚本
当前为
// ==UserScript==
// @name 当页开链
// @namespace http://greasyfork.icu/zh-CN/scripts/497533
// @version 3.0
// @description 全站通用型页内增强脚本
// @author none
// @match *://*/*
// @grant unsafeWindow
// @grant GM_registerMenuCommand
// @run-at document-body
// @connect *
// ==/UserScript==
(function() {
'use strict';
// 函数用于在当前标签页中打开链接
function openLinkInCurrentTab(url) {
window.location.href = url;
}
// 拦截所有点击事件
document.addEventListener('click', function(event) {
var target = event.target;
// 检查点击的元素以及其父元素是否是链接
while (target && target.tagName !== 'A') {
target = target.parentElement;
}
if (target && target.tagName === 'A') {
// 阻止默认行为,即在新标签页中打开链接
event.preventDefault();
// 获取链接的目标 URL
var url = target.href;
// 在当前标签页中打开链接
openLinkInCurrentTab(url);
}
});
// 拦截所有 window.open 调用
var originalOpen = window.open;
window.open = function(url, target, features) {
// 在当前标签页中打开链接
openLinkInCurrentTab(url);
};
// 监听 DOM 的变化,以处理后续加载的链接
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
// 检查是否有新链接被添加到 DOM
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach(function(node) {
if (node.tagName === 'A') {
// 阻止默认行为,即在新标签页中打开链接
node.addEventListener('click', function(event) {
event.preventDefault();
openLinkInCurrentTab(node.href);
});
}
});
}
});
});
// 开始观察 DOM 变化
observer.observe(document.body, { childList: true, subtree: true });
'use strict';
// 协议安全名单(2025标准)
const SAFE_PROTOCOLS = new Set([
'http:', 'https:', 'ftp:',
'mailto:', 'tel:', 'sms:'
]);
// Shadow DOM处理器(支持5级嵌套)
const processShadowRoot = (root, depth = 0) => {
if (depth > 5) return;
root.querySelectorAll('a, form').forEach(processElement);
root.querySelectorAll('*').forEach(node => {
if (node.shadowRoot) {
processShadowRoot(node.shadowRoot, depth + 1);
}
});
};
// 增强元素处理逻辑
const processElement = (element) => {
// 协议过滤
try {
const href = element.href?.toLowerCase() || '';
const protocol = new URL(href, location.href).protocol;
if (!SAFE_PROTOCOLS.has(protocol)) return;
} catch(e) {
return;
}
// 多维度属性清理
['target', 'onclick', 'data-target'].forEach(attr => {
element.removeAttribute(attr);
});
// 表单提交劫持
if (element.matches('form') && !element.__patched) {
element.__patched = true;
const originalSubmit = element.submit;
element.submit = function() {
this.target = '_self';
originalSubmit.call(this);
};
}
};
// 全局基础策略
const applyBaseStrategy = () => {
if (!document.querySelector('base')) {
const base = document.createElement('base');
base.target = '_self';
document.head.prepend(base);
}
};
// 智能观察器(性能优化版)
const initObserver = () => {
const observer = new MutationObserver(mutations => {
mutations.forEach(({ addedNodes, attributeName }) => {
// 处理新增节点
addedNodes.forEach(node => {
if (node.nodeType === 1) {
processElement(node);
processShadowRoot(node);
}
});
// 处理属性变更
if (attributeName === 'target') {
mutations.forEach(({ target }) => processElement(target));
}
});
});
observer.observe(document, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['target', 'href']
});
};
// 路由劫持层(支持现代框架)
const hijackRouting = () => {
const routerApis = [
history.pushState,
history.replaceState,
unsafeWindow.router?.navigate
];
routerApis.forEach(fn => {
const original = fn;
fn = (...args) => {
const result = original.apply(this, args);
setTimeout(() => {
document.querySelectorAll('a').forEach(processElement);
}, requestAnimationFrame(() => 0));
return result;
};
});
};
// 核心初始化
const main = () => {
if (window.self !== window.top) return;
applyBaseStrategy();
hijackRouting();
// 初始处理
document.querySelectorAll('a, form').forEach(processElement);
processShadowRoot(document);
// 动态处理
initObserver();
// 全局事件拦截
document.addEventListener('click', e => {
const target = e.composedPath()[0];
if (target.matches('a')) processElement(target);
}, { capture: true, passive: true });
// 强化window.open处理
unsafeWindow.open = function(url, target, ...args) {
return window.open(url, '_self', ...args);
};
};
// 启动逻辑
if (document.readyState === 'complete') {
main();
} else {
document.addEventListener('DOMContentLoaded', main);
}
// 调试功能
GM_registerMenuCommand('强制刷新处理', () => {
document.querySelectorAll('a, form').forEach(processElement);
processShadowRoot(document);
});
})();