uni-app中过滤emoji最稳妥方式是:Vue2用Vue.filter注册全局过滤器,Vue3建议封装工具函数;正则需覆盖Unicode补充平面并加u标志;@input中实时过滤更可控,注意iOS输入法和Array.from处理组合emoji。
直接在 main.js 或 main.ts 中注册过滤器最稳妥,避免每个页面重复写逻辑。注意 Vue2 和 Vue3 的 API 差异:
Vue.filter('noEmoji', (val) => {...}),注册后所有模板都能用 {{ text | noEmoji }}
app.config.globalProperties.$filters.noEmoji = (val) => {...},或通过 app.config.globalProperties 挂载,但模板中无法直接用管道符(|),需改用方法调用推荐 Vue2 项目用 Vue.filter;Vue3 项目建议封装成工具函数 + computed 或 watch 处理,别强求管道语法。
常见错误是只匹配 BMP 平面(u4E00-u9FA5 这类),漏掉 emoji 主要所在的 Unicode 补充平面(如 ?️???)。实际需同时处理:
/[u{1F600}-u{1F64F}]/u(表情符号)/[u{1F680}-u{1F6FF}]/u
/[u{1F700}-u{1F77F}]/u
/[u{1F900}-u{1F9FF}]/u
u200D 和 uFE0F
简单粗暴但实用的写法:val.replace(/[u{1F600}-u{1F64F}u{1F300}-u{1F5FF}u{1F680}-u{1F6FF}u{1F1E0}-u{1F1FF}u{200D}u{FE0F}]/gu, '') —— 注意必须加 u 标志,否则 u{...} 无效。
用户输入时,v-model 绑定的值还没进 data,靠过滤器只能处理显示层,无法阻止非法字符进入数据源。真正要「禁用」,得在输入事件里截断:
@input="onInput",而不是 @change(后者只在失焦/回车触发)onInput(val) { this.search = val.replace(/[u{1F600}-u{1F64F}u{1F300}-u{1F5FF}u{1F680}-u{1F6FF}u{1F1E0}-u{1F1FF}u{200D}u{FE0F}]/gu, ''); }特别注意 iOS 输入法:中文拼音状态下,@input 会先触发未上屏的拼音,再触发上屏后的汉字。若此时正则误删了拼音中间态,会导致输入卡顿。可加判断 if (event?.detail?.value) 确保取到最终值。
JavaScript 的 string.length 对 emoji 返回的是码元数(如 ?? 是 5),不是字符数。直接 str.substr(0, str.length - 1) 会切出乱码。
Array.from(str) 转成字符数组,再操作:Array.from(str).slice(0, -1).join('')
str.replace(/(?:[u2700-u27BF]|[uE000-uF8FF]|uD83C[uDC00-uDFFF]|uD83D[uDC00-uDFFF]|[u2011-u26FF]|uD83E[uDD10-uDDFF])/g, '').slice(0, -1) 不可靠,仍建议用 Array.from
复杂点在于组合型 emoji(??、?❤️?),它们由多个 Unicode 字符拼接而成,Array.from 能正确拆分,但正则很难全覆盖。真要高精度处理,得引入 grapheme-splitter 这类库,uni-app 小程序端需权衡包体积。