You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Violentmonkey用户脚本为网页货币数字添加美元符号

网页数值自动添加$符号的用户脚本修复方案

问题概述

需要给网页中无货币符号的数值(如25.00格式化为$25.00、3,100.00格式化为$3,100.00)添加$符号,使用Violentmonkey扩展实现,但现有脚本未生效,调整正则表达式后仍无效果。

原用户脚本代码

(function() {
    'use strict';

    function checkReadyState() {
        if (document.readyState === 'complete' || document.readyState === 'interactive') {
            // Regex to find numbers with two decimal places (with or without commas)
            const numberRegex = /\d+(,\d+)*\.\d\d/;

            // Find all text nodes (more general than specific elements)
            const textNodes = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
            let currentNode;

            // Function from StackOverflow
            const money = (amount, currency = 'USD', locale = 'en-US') => {
                return Intl.NumberFormat(locale, {
                    style: 'currency',
                    currency
                }).format(amount);
            }

            while (currentNode = textNodes.nextNode()) {
                const text = currentNode.nodeValue;
                const modifiedText = text.replace(numberRegex, (match) => {
                    // Don't add '$' if it already exists
                    if (match.startsWith('$')) {
                        return match;
                    } else {
                        const amount = parseFloat(match.replace(/,/g, '')); // Remove commas
                        return money(amount);
                    }
                });
                if (modifiedText !== text) {
                    const newNode = document.createTextNode(modifiedText);
                    currentNode.parentNode.replaceChild(newNode, currentNode);
                }
            }
        } else {
            // Wait for the document to be ready
            document.addEventListener('DOMContentLoaded', checkReadyState);
        }
    }

    // Call the function initially
    checkReadyState();
})();

网页示例代码

<p>25.00</p>

<p>3,100.00</p>

<div data-cellname="[object Object]" class="css-12hdbj5 css-nil">3,105.00</div>
<br>

<span data-testid="__global!balance-1a1d49c3-9cb8-4c67-896c-0122ac627f08" data-cellname="__global!balance-1a1d49c3-9cb8-4c67-896c-0122ac627f08" class=" css-1ai95jy">45.14</span>
<br>

<span class=" css-bs1bqe">90.00</span>
<br>

问题原因分析

  • 正则表达式缺陷:原正则缺少全局匹配标志(g),仅替换每个文本节点的第一个匹配项;且无单词边界(\b),可能误匹配长文本中的片段。
  • DOM遍历问题:使用TreeWalker时,替换文本节点会打乱遍历顺序,导致部分节点被跳过。
  • 未处理动态内容:脚本仅在初始DOM加载完成时运行一次,无法处理网页后续异步加载的数值。

修复后的脚本代码

(function() {
    'use strict';

    // 格式化数值为带$的货币格式
    const formatCurrency = (amountStr) => {
        // 移除千分位逗号,转换为数字
        const amount = parseFloat(amountStr.replace(/,/g, ''));
        if (isNaN(amount)) return amountStr;
        
        return new Intl.NumberFormat('en-US', {
            style: 'currency',
            currency: 'USD'
        }).format(amount);
    };

    // 遍历并处理文本节点
    function processTextNodes(node) {
        if (node.nodeType === Node.TEXT_NODE) {
            const originalText = node.nodeValue;
            // 匹配独立的、带两位小数的数值(支持千分位),全局替换
            const modifiedText = originalText.replace(/\b\d{1,3}(,\d{3})*\.\d{2}\b/g, (match) => {
                // 跳过已带$的数值
                if (match.startsWith('$')) return match;
                return formatCurrency(match);
            });
            
            if (modifiedText !== originalText) {
                const newTextNode = document.createTextNode(modifiedText);
                node.parentNode.replaceChild(newTextNode, node);
            }
        } else if (node.nodeType === Node.ELEMENT_NODE && !['SCRIPT', 'STYLE'].includes(node.tagName)) {
            // 递归处理子节点,跳过脚本和样式标签
            Array.from(node.childNodes).forEach(child => processTextNodes(child));
        }
    }

    // 处理当前DOM内容
    function processPage() {
        processTextNodes(document.body);
    }

    // 监听DOM变化,处理动态加载内容
    const observer = new MutationObserver((mutations) => {
        mutations.forEach(mutation => {
            mutation.addedNodes.forEach(node => {
                if (node.nodeType === Node.ELEMENT_NODE) {
                    processTextNodes(node);
                }
            });
        });
    });

    // 初始化执行
    function init() {
        processPage();
        // 开始监听DOM变化
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    // 确保DOM加载完成后执行
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();

关键改动说明

  • 正则优化:使用/\b\d{1,3}(,\d{3})*\.\d{2}\b/g,\b确保匹配独立数值,\d{1,3}(,\d{3})*准确匹配千分位格式,g实现全局替换。
  • 遍历方式调整:改用递归遍历文本节点,避免TreeWalker的遍历中断问题,同时跳过SCRIPT和STYLE标签防止误修改。
  • 动态内容处理:添加MutationObserver监听DOM变化,自动处理后续加载的数值内容。
  • 格式化函数优化:增加数值有效性判断,避免转换失败导致的异常。

内容的提问来源于stack exchange,提问作者Michael Gunter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 16:57:16