动态文字替换器

进入网页时自动替换,优化界面显示,美化悬浮窗

// ==UserScript==
// @name         动态文字替换器
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  进入网页时自动替换,优化界面显示,美化悬浮窗
// @author       handsometaoa
// @match        http://*/*
// @match        https://*/*
// @license      GPL-3.0 License
// ==/UserScript==

(function () {
    'use strict';
    // 创建悬浮弹框
    const popup = document.createElement('div');
    popup.id = 'textReplacerPopup';
    popup.style.position = 'fixed';
    popup.style.top = '10px';
    popup.style.right = '10px';
    popup.style.backgroundColor = '#ffffff';
    popup.style.border = '1px solid #ddd';
    popup.style.borderRadius = '8px';
    popup.style.padding = '15px';
    popup.style.boxShadow = '0 4px 10px rgba(0, 0, 0, 0.1)';
    popup.style.zIndex = '9999';
    popup.style.width = '320px';
    popup.style.display = 'none'; // 默认隐藏

    // 创建缩小后的悬浮窗
    const miniPopup = document.createElement('div');
    miniPopup.id = 'textReplacerMiniPopup';
    miniPopup.style.position = 'fixed';
    miniPopup.style.top = '10px';
    miniPopup.style.right = '10px';
    miniPopup.style.backgroundColor = '#007bff';
    miniPopup.style.color = '#ffffff';
    miniPopup.style.borderRadius = '50%';
    miniPopup.style.width = '40px';
    miniPopup.style.height = '40px';
    miniPopup.style.display = 'flex';
    miniPopup.style.alignItems = 'center';
    miniPopup.style.justifyContent = 'center';
    miniPopup.style.boxShadow = '0 2px 6px rgba(0, 0, 0, 0.2)';
    miniPopup.style.zIndex = '9999';
    miniPopup.style.cursor = 'pointer';
    miniPopup.textContent = '替';
    miniPopup.style.textAlign = 'center';
    miniPopup.style.lineHeight = '40px'; // 行高等于容器高度

    // 弹框标题
    const title = document.createElement('h3');
    title.textContent = '文字替换器';
    title.style.margin = '0 0 15px 0';
    title.style.fontSize = '18px';
    title.style.color = '#333';
    popup.appendChild(title);

    // 替换规则列表
    const rulesList = document.createElement('div');
    rulesList.style.marginBottom = '15px';
    popup.appendChild(rulesList);

    // 原始文字输入框
    const originalLabel = document.createElement('label');
    originalLabel.textContent = '原始文字:';
    originalLabel.style.display = 'block';
    originalLabel.style.marginBottom = '5px';
    originalLabel.style.color = '#555';
    popup.appendChild(originalLabel);

    const originalInput = document.createElement('input');
    originalInput.type = 'text';
    originalInput.style.width = '100%';
    originalInput.style.padding = '8px';
    originalInput.style.marginBottom = '15px';
    originalInput.style.border = '1px solid #ddd';
    originalInput.style.borderRadius = '4px';
    popup.appendChild(originalInput);

    // 替换文字输入框
    const replacementLabel = document.createElement('label');
    replacementLabel.textContent = '替换文字:';
    replacementLabel.style.display = 'block';
    replacementLabel.style.marginBottom = '5px';
    replacementLabel.style.color = '#555';
    popup.appendChild(replacementLabel);

    const replacementInput = document.createElement('input');
    replacementInput.type = 'text';
    replacementInput.style.width = '100%';
    replacementInput.style.padding = '8px';
    replacementInput.style.marginBottom = '15px';
    replacementInput.style.border = '1px solid #ddd';
    replacementInput.style.borderRadius = '4px';
    popup.appendChild(replacementInput);

    // 添加规则按钮
    const addButton = document.createElement('button');
    addButton.textContent = '添加规则';
    addButton.style.marginRight = '10px';
    addButton.style.padding = '8px 12px';
    addButton.style.backgroundColor = '#28a745';
    addButton.style.color = '#fff';
    addButton.style.border = 'none';
    addButton.style.borderRadius = '4px';
    addButton.style.cursor = 'pointer';
    popup.appendChild(addButton);

    // 保存并替换按钮
    const saveButton = document.createElement('button');
    saveButton.textContent = '保存并替换';
    saveButton.style.marginRight = '10px';
    saveButton.style.padding = '8px 12px';
    saveButton.style.backgroundColor = '#007bff';
    saveButton.style.color = '#fff';
    saveButton.style.border = 'none';
    saveButton.style.borderRadius = '4px';
    saveButton.style.cursor = 'pointer';
    popup.appendChild(saveButton);

    // 关闭按钮
    const closeButton = document.createElement('button');
    closeButton.textContent = '关闭';
    closeButton.style.padding = '8px 12px';
    closeButton.style.backgroundColor = '#6c757d';
    closeButton.style.color = '#fff';
    closeButton.style.border = 'none';
    closeButton.style.borderRadius = '4px';
    closeButton.style.cursor = 'pointer';
    popup.appendChild(closeButton);

    // 将弹框和缩小悬浮窗添加到页面
    document.body.appendChild(popup);
    document.body.appendChild(miniPopup);

    // 从 localStorage 加载保存的规则
    let savedRules = JSON.parse(localStorage.getItem('textReplacerRules')) || [];

    // 显示保存的规则
    function renderRules() {
        rulesList.innerHTML = '';
        savedRules.forEach((rule, index) => {
            const ruleDiv = document.createElement('div');
            ruleDiv.id = 'replaceRuleDiv';
            ruleDiv.style.marginBottom = '10px';
            ruleDiv.style.padding = '8px';
            ruleDiv.style.backgroundColor = '#f8f9fa';
            ruleDiv.style.border = '1px solid #ddd';
            ruleDiv.style.borderRadius = '4px';
            ruleDiv.style.display = 'flex';
            ruleDiv.style.justifyContent = 'space-between';
            ruleDiv.style.alignItems = 'center';

            const ruleText = document.createElement('span');
            ruleText.textContent = `${rule.original} → ${rule.replacement}`;
            ruleText.style.color = '#333';
            ruleDiv.appendChild(ruleText);

            const deleteButton = document.createElement('button');
            deleteButton.textContent = '删除';
            deleteButton.style.padding = '4px 8px';
            deleteButton.style.backgroundColor = '#dc3545';
            deleteButton.style.color = '#fff';
            deleteButton.style.border = 'none';
            deleteButton.style.borderRadius = '4px';
            deleteButton.style.cursor = 'pointer';
            deleteButton.addEventListener('click', () => {
                savedRules.splice(index, 1);
                localStorage.setItem('textReplacerRules', JSON.stringify(savedRules));
                renderRules();
            });

            ruleDiv.appendChild(deleteButton);
            rulesList.appendChild(ruleDiv);
        });
    }

    // 初始化显示规则
    renderRules();

    // 添加规则
    addButton.addEventListener('click', () => {
        const original = originalInput.value.trim();
        const replacement = replacementInput.value.trim();

        if (!original || !replacement) {
            alert("请输入完整的原始文字和替换文字!");
            return;
        }

        savedRules.push({original, replacement});
        localStorage.setItem('textReplacerRules', JSON.stringify(savedRules));
        renderRules();

        // 清空输入框
        originalInput.value = '';
        replacementInput.value = '';
    });

    // 保存并替换文字
    saveButton.addEventListener('click', () => {
        if (savedRules.length === 0) {
            alert("请先添加替换规则!");
            return;
        }

        // 递归遍历所有文本节点并替换文字
        function replaceTextInNode(node) {
            if (node.nodeType === Node.TEXT_NODE) {
                let text = node.nodeValue;
                savedRules.forEach((rule) => {
                    text = text.replace(new RegExp(rule.original, 'g'), rule.replacement);
                });
                node.nodeValue = text;
            } else if (node.nodeType === Node.ELEMENT_NODE && !['SCRIPT', 'STYLE'].includes(node.tagName)) {
                if(node.id === 'replaceRuleDiv'){
                    return;
                }
                for (let child of node.childNodes) {
                    replaceTextInNode(child);
                }
            }
        }

        // 开始替换
        replaceTextInNode(document.body);

        // alert("文字替换完成!");

        // 缩小弹框
        popup.style.display = 'none';
        miniPopup.style.display = 'block';
    });

    // 关闭弹框
    closeButton.addEventListener('click', () => {
        popup.style.display = 'none';
        miniPopup.style.display = 'block';
    });

    // 展开弹框
    miniPopup.addEventListener('click', () => {
        popup.style.display = 'block';
        miniPopup.style.display = 'none';
    });

    // 进入网页时自动替换
    if (savedRules.length > 0) {
        saveButton.click(); // 自动触发保存并替换
    }

})();