自己搓一个,凑合用吧,对b站有效
(2025 7/30更新,欢迎提bug)
// ==UserScript==
// @name !✅双击文本打开链接
// @namespace http://tampermonkey.net/
// @version 3.3
// @description 双击文本时,打开鼠标所在位置最近的链接,支持 Shadow DOM 和多个链接判断
// @author psycho
// @match *://*/*
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
const urlRegexGlobal = /\b((?:https?:\/\/|www\.)[-\w@:%_+.~#?&//=]+|[\w.-]+\.(?:com|net|org|cn|io|me|tv|cc|xyz|info)(?:\/[\w@:%_+.~#?&//=]*)?)\b/gi;
function getTextNodesIn(el) {
const nodes = [];
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, {
acceptNode: node => node.nodeValue.trim() ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
});
while (walker.nextNode()) nodes.push(walker.currentNode);
return nodes;
}
document.addEventListener('dblclick', (event) => {
const target = event.composedPath()[0];
if (!target || !(target instanceof Element)) return;
const textNodes = getTextNodesIn(target);
const mouseX = event.clientX;
const mouseY = event.clientY;
let closestUrl = null;
let minDistance = Infinity;
for (const textNode of textNodes) {
const fullText = textNode.nodeValue;
urlRegexGlobal.lastIndex = 0;
let match;
while ((match = urlRegexGlobal.exec(fullText)) !== null) {
const startOffset = match.index;
const endOffset = startOffset + match[0].length;
const range = document.createRange();
range.setStart(textNode, startOffset);
range.setEnd(textNode, endOffset);
const rects = range.getClientRects();
for (const rect of rects) {
const dx = mouseX - (rect.left + rect.right) / 2;
const dy = mouseY - (rect.top + rect.bottom) / 2;
const distance = Math.sqrt(dx * dx + dy * dy);
if (
mouseX >= rect.left && mouseX <= rect.right &&
mouseY >= rect.top && mouseY <= rect.bottom &&
distance < minDistance
) {
minDistance = distance;
closestUrl = match[0];
}
}
}
}
if (closestUrl) {
const fullUrl = /^https?:\/\//i.test(closestUrl) ? closestUrl : 'http://' + closestUrl;
console.log('[双击] 最近链接:', fullUrl);
window.open(fullUrl, '_blank');
} else {
console.warn('[双击] 没有找到匹配链接');
}
}, { capture: true, passive: true });
})();