不能用 value.substr(0, 1) + '*' 是因 substr 按字节截取、不识别 Unicode 边界,且未按姓名长度分情况处理:2 字不脱敏,3 字为“首尾”,≥4 字为“首+(len-2)个+尾”,须用 Array.from() 确保正确切分中文与 emoji。

直接用过滤器隐藏姓名中间字是可行的,但必须按字数分情况处理,不能简单截取首字符加星号——否则“李四”会变成“李*”,“欧阳修文”会变成“欧*”,漏掉关键逻辑。
为什么不能用 value.substr(0, 1) + '*'
这种写法看似省事,实际在真实姓名场景下会出错:
• “李四”(2字)本不该脱敏,却显示为“李*”
• “王小明”(3字)应为“王*明”,结果变成“王*”
• “司马相如”(4字)应为“司**如”,而非“司*”
根本问题是:substr 按字节切,不识别 Unicode 字符边界;且没做长度分支判断,把所有名字都当成 ≥2 字统一处理。
hideName 过滤器必须按字符长度分三档实现
正确逻辑只保留姓氏(首字)和名的尾字(如有),中间全部替换为星号,且必须用 Array.from() 处理中文、emoji 等多码点字符:
- 长度为 2:不脱敏,原样返回(如“李四” → “李四”)
- 长度为 3:首字 + “*” + 尾字(如“王小明” → “王*明”)
- 长度 ≥4:首字 +
'*'.repeat(len - 2)+ 尾字(如“欧阳修文” → “欧**文”)
示例代码(放在 @/common/filters/index.js):
Vue.filter('hideName', function(value) {
if (!value || typeof value !== 'string') return ''
const chars = Array.from(value)
const len = chars.length
if (len === 2) return value
if (len === 3) return chars[0] + '*' + chars[2]
if (len >= 4) return chars[0] + '*'.repeat(len - 2) + chars[len - 1]
return value
})模板中调用时严禁混入 v-model
过滤器只用于展示,不能参与双向绑定流程。常见错误写法:
- ❌
<input v-model="userInfo.name" /> {{ userInfo.name | hideName }}—— 输入过程中实时脱敏,体验错乱 - ❌ 在
@input里手动调用hideName改原始数据 —— 破坏响应式源头,后续无法还原
正确做法是严格分离场景:
• 编辑态(表单):直接用 userInfo.name,不经过任何过滤
• 展示态(资料页、列表):仅用 {{ userInfo.name | hideName }}
最容易被忽略的是:小程序端 filters 实际不执行,H5 能看到效果不代表真机可用。如果项目需全端一致,得改用计算属性或工具函数封装该逻辑,而不是依赖模板语法。


















