intl.numberformat('en-us', { style: 'percent' }) 默认将输入值乘以100再加%符号;传入0.12得12%,若后端返回整数12则需先除以100,否则会显示1200%。

percent模式默认会乘以100,传入0.12要写成0.12而不是12
Intl.NumberFormat(en-US, { style: 'percent' }) 会把输入数字自动 ×100 再加 % 符号。这是最容易出错的地方:如果你原始数据已经是“百分比值”(比如后端返回 12 表示 12%),直接传进去会变成 1200%;如果原始是小数形式(0.12),才符合预期。
常见错误现象:new Intl.NumberFormat('zh-CN', { style: 'percent' }).format(12) → "1,200%"(明显不对)
- 后端返回整数百分比(如
12、-5):传入前除以 100,即12 / 100 - 后端返回小数(如
0.12、-0.05):直接传入即可 - 不确定来源时,先检查数值量级:若多数在 0–1 之间,按小数处理;若在 1–100+,大概率是整数百分比
控制小数位数要用 minimumFractionDigits / maximumFractionDigits,不是 minimumSignificantDigits
百分比格式下想固定显示一位小数(如 "12.3%" 而非 "12%" 或 "12.34%"),必须用 minimumFractionDigits 和 maximumFractionDigits。用 minimumSignificantDigits 无效,它作用于整个数字的有效位,不适用于 percent 模式的小数精度控制。
示例:new Intl.NumberFormat('en-US', { style: 'percent', minimumFractionDigits: 1, maximumFractionDigits: 1 }).format(0.1234) → "12.3%"
- 设
minimumFractionDigits: 2时,0.1会变成"10.00%"(补零) - 设
maximumFractionDigits: 0时,0.127会四舍五入为"13%" - 中文 locale(如
zh-CN)下,千分位分隔符默认不出现(1234.56%不会变成1,234.56%),这是正常行为,不是 bug
负百分比的符号位置和括号行为取决于 locale,不能靠 CSS 修正
不同语言环境下,负百分比的表示方式不同:en-US 默认输出 "-12.5%",而 de-DE 可能输出 "-12,5 %"(空格位置不同),zh-CN 则是 "-12.5%"。更关键的是:有些 locale(如 en-GB)支持用 signDisplay: 'parentheses' 输出 "(12.5%)",但并非所有 locale 都支持该选项——Chrome 支持,Safari 16+ 才开始支持,旧版 Safari 会忽略该配置并仍显示负号。
- 若需强一致的负号样式(比如统一用括号),不要依赖
signDisplay,改用条件判断 + 字符串拼接 -
locale影响空格、小数点/逗号、% 符号位置,切换 locale 前务必在目标浏览器中实测渲染效果 - 避免在 format 结果上再用
.replace(/%/g, '%')替换全角符号——这会破坏可访问性(screen reader 可能读错)且影响排序逻辑
报表中高频调用时建议缓存 formatter 实例,别每次 new
Intl.NumberFormat 构造开销不小,尤其在表格渲染上百行、每行多个百分比字段时。反复 new Intl.NumberFormat(...) 会明显拖慢 React 渲染或 Vue 更新速度。
- 把 formatter 提到组件外或模块顶层缓存:
const percentFormatter = new Intl.NumberFormat('zh-CN', { style: 'percent', minimumFractionDigits: 1 }) - 不要在 render 函数里创建新实例,哪怕参数完全一样
- 若需动态 locale 或精度,用 Map 缓存不同配置组合:
formatters.get(`${locale}-${min}-${max}`) ??= new Intl.NumberFormat(...) - 注意:formatter 实例不是纯函数,它依赖当前环境的 ICU 数据,不可跨 iframe 或 Service Worker 共享
new 就可能让帧率掉到 30fps 以下。










