// ==UserScript==
// @name 网页文本转链接
// @description 网页中文本转为可点击链接 添加颜色下划线
// @version 2.1
// @author WJ
// @match *://*/*
// @license MIT
// @grant none
// @namespace https://greasyfork.org/users/914996
// @downloadURL none
// ==/UserScript==
(function() {
'use strict';
const ZZ = /\b([\w.?:/=%-]{3,}\.(?:app|aero|aer|art|asia|beer|biz|cat|cc|chat|ci|cloud|club|cn|com|cool|coop|co|dev|edu|email|fit|fun|gov|govt|group|hk|host|icu|info|ink|int|io|jobs|kim|love|ltd|luxe|me|mil|mobi|moe|museum|name|net|nl|network|one|online|org|plus|post|press|pro|red|ren|run|ru|shop|site|si|space|store|tech|tel|top|travel|tv|tw|uk|us|video|vip|wang|website|wiki|wml|work|ws|xin|xyz|yoga|zone)(?!\w)[\w.?:/=%-]*)/gi;
// 添加样式
document.head.insertAdjacentHTML('beforeend',
''
);
// 一次性收集所有文本节点
const treeWalker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
{
acceptNode: (node) => {
const parent = node.parentNode;
// 预过滤:跳过不需要处理的节点
if (parent.tagName === 'SCRIPT' ||
parent.tagName === 'STYLE' ||
parent.tagName === 'TEXTAREA' ||
parent.tagName === 'A' ||
parent.isContentEditable) {
return NodeFilter.FILTER_REJECT;
}
return NodeFilter.FILTER_ACCEPT;
}
}
);
// 批量处理节点
const nodes = [];
while (treeWalker.nextNode()) nodes.push(treeWalker.currentNode);
// 高效处理循环
for (let i = 0, len = nodes.length; i < len; i++) {
const node = nodes[i];
const text = node.textContent;
// 快速跳过不含域名的文本
if (!ZZ.test(text)) continue;
ZZ.lastIndex = 0; // 重置正则
// 创建替换内容
let newHtml = text.replace(ZZ, match => {
return `${match}`;
});
// 执行DOM替换
if (newHtml !== text) {
const span = document.createElement('span');
span.innerHTML = newHtml;
node.replaceWith(span);
}
}
})();