HTML本身不能做手机号脱敏,真正有效的是服务端输出前处理或前端JS渲染时实时替换;需先清洗非数字字符、校验长度,再分段替换,且必须在数据绑定前完成,避免明文暴露。

HTML 本身不能做手机号脱敏,所有试图在纯 HTML 标签里“加个属性”或“写个注释”就声称脱敏的做法,都是无效的。真正起作用的只有服务端输出前处理,或前端 JS 渲染时实时替换。
为什么直接在 HTML 里写 138****1234 不算脱敏
这种写法只是把脱敏结果硬编码进源码,意味着:原始数据根本没出现过,也谈不上“脱敏”;更关键的是,它无法响应不同权限、不同场景的动态策略(比如客服看前3后4,实习生只能看前3后2)。一旦业务规则变,就得改 HTML 模板,维护成本高,还容易漏改。
常见错误现象包括:
- 在 Vue/React 模板里写死
{{ user.phone | maskPhone }},但maskPhone过滤器没做空值/长度校验,遇到null或"138"就报错或拼出138**** - 用
innerHTML插入含明文手机号的字符串,再用querySelectorAll("td.phone")遍历替换——页面会先闪一下完整号码 - 正则写成
/^1[3-9]\d{9}$/去匹配,但用户输入的是138-0013-8000或+86 13800138000,直接不匹配,脱敏失效
phone.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2") 的坑与修正
这行代码看着简洁,但上线后常出问题。核心问题是:它假设输入一定是 11 位纯数字,且结构规整。现实中远非如此。
立即学习“前端免费学习笔记(深入)”;
安全做法是先清洗、再校验、最后替换:
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
- 用
phone.replace(/\D/g, "")去掉所有非数字字符(空格、横杠、+、括号等) - 检查清洗后长度是否为 11,不是就直接返回原值(不强行脱敏)
- 再用
substr_replace(PHP)或slice+ 字符串拼接(JS)做替换,避免正则捕获失败时返回空或异常 - 如果要兼容固话(如
010-12345678),得单独判断清洗后长度是否为 10 或 11,分支处理
JS 示例(带防护):
function maskPhone(phone) {
if (!phone || typeof phone !== 'string') return phone;
const clean = phone.replace(/\D/g, '');
if (clean.length !== 11) return phone;
return clean.slice(0, 3) + '****' + clean.slice(7);
}
Vue/React 中该在哪一层做脱敏
必须在数据绑定前完成,不能依赖 DOM 渲染后再操作。否则存在明文暴露窗口期,尤其在 SSR 或快速首屏场景下更明显。
推荐位置:
- Vue:在
computed或setup()里调用脱敏函数,确保{{ maskedPhone }}绑定的是已处理值 - React:在
useMemo或组件顶层变量中处理,不要在return内联写phone.replace(...) - 服务端模板(如 Twig、Thymeleaf):直接在渲染层调用
mask_phone(phone),最稳妥,无前端风险
绝对避免:
- 在
mounted/useEffect里查 DOM 并修改textContent - 把脱敏逻辑写在
v-html或dangerouslySetInnerHTML的内容里 - 用 CSS
text-security: disc伪装脱敏——审查元素一眼看到明文
真正难的不是写对一行正则,而是让脱敏行为稳定嵌入整个数据流:从接口返回、状态管理、到最终渲染,每个环节都可能绕过或破坏脱敏逻辑。尤其是当同一个字段要在表格、弹窗、导出 Excel、甚至埋点日志里复用时,分散的脱敏调用极易遗漏或不一致。


















